Controlli di connessione

I controlli della connessione limitano le connessioni (e quindi i blocchi) che possono connettersi tra loro.

I controlli della connessione sono utili per i tipi di modellazione. Ad esempio, i seguenti tre blocchi non hanno attività connesse, perché rappresentano codice che restituisce tipi diversi:

Un blocco di elenco vuoto, collegato a un blocco radice quadrato, collegato a un blocco maiuscolo

È possibile utilizzare i controlli della connessione per impedire la connessione di questi blocchi. In questo modo gli utenti ricevono un feedback immediato e si evitano molti semplici errori.

Funzionamento

Ogni connessione può essere associata a un "controllo della connessione", ovvero un array di stringhe con null.

Possono connettersi due connessioni se:

  1. Sono tipi compatibili (ad es. un'uscita che si collega a un ingresso).
  2. Hanno in comune almeno una stringa nel controllo della connessione.

Ad esempio, i seguenti due controlli potrebbero connettersi, perché condividono la stringa 'apple':

['apple', 'ball', 'cat']
['apple', 'bear', 'caterpillar']

Non è stato possibile connettere questi due controlli perché non condividono alcuna stringa:

['apple', 'ball', 'cat']
['ape', 'bear', 'caterpillar']

C'è un altro caso speciale. Se uno degli array è null, anche le due connessioni possono connettersi. In questo modo puoi definire connessioni che possono connettersi a qualsiasi cosa.

null
['ape', 'bear', 'caterpillar]

Imposta controlli

Per impostazione predefinita, tutte le connessioni hanno un controllo della connessione null, il che significa che possono connettersi a qualsiasi cosa. I controlli della connessione devono essere assegnati manualmente.

Il modo in cui assegni i controlli della connessione alle connessioni varia a seconda che utilizzi le definizioni di blocco JSON o JavaScript.

JSON

Per le connessioni di primo livello, assegni il controllo direttamente alla proprietà che definisce la connessione. Il valore assegnato può essere null, una stringa (che diventa l'unica voce nel controllo della connessione) o un array di stringhe.

{
  'type': 'custom_block',

  'output': null,
  'nextStatement': 'a connection check entry',
  'previousStatement': ['four', 'connection', 'check', 'entries']
}

Per gli input, puoi assegnare il controllo a una proprietà check della definizione dell'input. Se la proprietà check non esiste, il controllo viene considerato null. Il valore assegnato può essere una stringa o un array di stringhe.

{
  'type': 'custom_block',
  'message0': '%1 %2',

  'args0': [
    {
      'type': 'input_value',
      'check': 'a connection check entry'
    },
    {
      'type': 'input_statement',
      'check': ['four', 'connection', 'check', 'entries']
    }
  ]
}

JavaScript

Per le connessioni di primo livello, puoi passare il controllo direttamente al metodo che definisce la connessione. Se non superi un valore, il controllo viene considerato null. Il valore passato può essere una stringa (che diventa l'unica voce nel controllo della connessione) o un array di stringhe.

Blockly.Blocks['custom_block'] = {
  init: function() {
    this.setOutput(true); // null check
    this.setNextStatement(true, 'a connection check entry');
    this.setPreviousStatement(true, ['four', 'connection', 'check', 'entries']);
  }
}

Per gli input, puoi passare il controllo al metodo setCheck, dopo aver definito l'input. Se il metodo setCheck non viene chiamato, il controllo viene considerato null. Il valore trasmesso può essere una stringa o un array di stringhe.

Blockly.Blocks['custom_block'] = {
  init: function() {
    this.appendValueInput('NAME')
        .setCheck('a connection check entry');
    this.appendStatementInput('NAME')
        .setCheck(['four', 'connection', 'check', 'entries']);
  }
}

Stringhe di controllo integrate

I blocchi integrati hanno controlli della connessione con i valori 'Array', 'Boolean', 'Colour', 'Number' e 'String'. Se vuoi che i blocchi si interoperino con i blocchi integrati, puoi utilizzare questi valori per renderli compatibili.

Esempi di valori

Quando definisci i controlli della connessione per input e output, in genere devi considerare i controlli come una rappresentazione dei tipi.

I controlli degli input devono includere ogni "tipo" accettato e i controlli degli output devono includere esattamente ciò che "restituiscono".

Accettare un solo tipo

Nel caso più semplice in cui vuoi creare un blocco che "accetta" o "restituisce" un tipo, devi includere quel tipo nel controllo della connessione della connessione.

un blocco di valori che accetta un singolo tipo

Accetta più tipi

Per creare un blocco che "accetta" più tipi, devi includere ogni tipo accettato nel controllo della connessione dell'input.

un blocco valore che accetta più tipi

Per convenzione, se a volte un output può essere accettato in più situazioni (ad es. se a volte consenti l'utilizzo di numeri come stringhe), l'output dovrebbe essere più restrittivo e gli input dovrebbero essere più permissivi. Questa convenzione fa sì che gli output non si connettano laddove non sono supportati.

Accetta qualsiasi tipo

Per creare un blocco che "accetta" qualsiasi tipo, devi impostare il controllo della connessione dell'input su null.

un blocco valore che accetta qualsiasi tipo

Restituisci sottotipi

Per creare un blocco che "restituisce" un sottotipo, devi includere sia il tipo sia il supertipo nel controllo della connessione dell'output.

un blocco di valore che restituisce il tipo e il supertipo

Nel caso di sottotipi, è consentito avere più controlli in un controllo dell'output, perché il blocco"restituisce sempre entrambi i tipi.

Restituisci tipi con parametri

Per creare un blocco che "restituisce" un tipo parametrizzato, devi includere sia la versione con parametri sia la versione senza parametri nel controllo della connessione dell'output.

A seconda di quanto vuoi sia rigoroso il blocco della lingua, puoi anche includere le variazioni del tipo.

un blocco di valori che restituisce il tipo con parametri e il tipo
senza parametri

Proprio come per i sottotipi, in questo caso è consentito avere più controlli in un controllo dell'output, perché il blocco"restituisce sempre entrambi i tipi.

Esempi di stack o istruzioni

Esistono alcuni modi comuni in cui gli sviluppatori definiscono i controlli per le connessioni precedenti e successive. In genere si pensa che questi limitino l'ordine dei blocchi.

Le connessioni successive devono includere i blocchi che devono seguire quello attuale e le connessioni precedenti devono includere "è" il blocco attuale.

Mantieni in ordine i blocchi

Per creare un insieme di blocchi che si connettono in un ordine definito, devi includere i blocchi che devono seguire quello attuale nel controllo della connessione successivo e qual è il blocco attuale nel controllo della connessione precedente.

che hanno un ordine forzato

Consenti molti blocchi centrali

Per creare un insieme di blocchi ordinati che consentono molti blocchi centrali, devi includere almeno una voce del controllo di connessione precedente del blocco centrale nel successivo controllo di connessione del blocco centrale. In questo modo il blocco può essere seguito più di se stesso.

che consentono molti blocchi centrali

Non consentire blocchi centrali

Per creare un insieme di blocchi ordinati in cui i blocchi centrali sono facoltativi, devi includere almeno una voce del controllo della connessione precedente del blocco centrale e del controllo della connessione precedente dell'ultimo blocco nel controllo della connessione successivo del primo blocco. In questo modo, il primo blocco può essere seguito da un blocco centrale o da un ultimo blocco.

blocchi di istruzioni che non consentono blocchi centrali

Stack uno o l'altro

Per creare un blocco che possa essere seguito solo da blocchi di un gruppo o da blocchi da un altro (e non da entrambi), devi fare due cose:

  1. Devi includere almeno una voce di entrambi i controlli della connessione precedenti dei gruppi nel controllo della connessione successivo del primo blocco.

  2. Devi definire i controlli di connessione successivi dei gruppi in modo da includere solo i valori presenti nei controlli di connessione precedenti (in modo che possano essere seguiti solo da blocchi dello stesso gruppo).

che possono essere seguiti da più blocchi di un tipo
o da più blocchi di un altro, ma non entrambi

Limitazioni

Questo sistema è piuttosto solido e può risolvere molti casi d'uso, ma presenta alcune limitazioni.

Limitare il contesto generale

Questo sistema non supporta di per sé la limitazione del "contesto maggiore" in cui è consentita la connessione di una connessione. Ad esempio, non puoi dire che un blocco break può esistere solo all'interno di un blocco loop. Il sistema di controllo della connessione prende in considerazione solo le due connessioni immediate che sono connesse.

Puoi supportare questa situazione utilizzando il sistema di eventi per ascoltare gli eventi di spostamento dei blocchi e verificare se il blocco è posizionato in modo errato.

Blockly.Blocks['custom_block'] = {
  init: function() { }

  onchange: function(e) {
    if (this.workspace.isDragging()) return;
    if (e.type !== Blockly.Events.BlockMove) return;
    if (!this.getSurroundLoop()) this.outputConnection.disconnect();
  }

  loopTypes: new Set(); // Your valid *block types* (not connection checks).

  getSurroundLoop: function () {
    let block = this.getSurroundParent();
    do {
      if (loopTypes.has(block.type)) return block;
      block = block.getSurroundParent();
    } while (block);
    return null;
  },
}

Tipi generici

Questo sistema non supporta di per sé la definizione di tipi generici. Ad esempio, non puoi creare un blocco "Identity", che "restituisce" qualunque sia l'input.

Puoi in qualche modo supportare questa modifica modificando attivamente il controllo della connessione sull'output del blocco in modo che corrisponda al suo input. che puoi fare usando il sistema di eventi per ascoltare e bloccare gli eventi di spostamento.

Blockly.Blocks['custom_block'] = {
  init: function() { }

  onchange: function(e) {
    if (e.type !== Blockly.Events.BlockMove) return;
    this.setOutput(
        true, this.getInputTargetBlock()?.outputConnection.getCheck());
  }
}

Tuttavia, se il blocco collegato è anche generico, non funziona correttamente. Non c'è una soluzione valida per questa richiesta.

Controlli della connessione

Se questo sistema non funziona per il tuo caso d'uso, puoi anche modificare il modo in cui vengono confrontati i controlli della connessione creando uno strumento di controllo delle connessioni personalizzato.

Ad esempio, se vuoi creare un sistema più avanzato che gestisca alcune limiti di questo modello, puoi creare uno strumento di controllo connessione personalizzato.