Non ho idea di come scrivere un buon titolo per questa domanda.
Sto pensando di introdurre un operatore in una DSL che rende accessibili gli identificatori nascosti (come le variabili). Pensa a this.foo
in Java o C # per accedere a un membro nascosto da un foo
locale. O base.bar
quando bar
è un membro nella classe corrente. Chiamiamo questo "accesso esplicito a un ambito che racchiude".
I destinatari del DSL sono non programmatori / principianti, che non dovrebbero essere richiesti per comprendere (in dettaglio) gli ambiti in cui stanno lavorando. Quindi l'idea è di introdurre invece un operatore che salta un'occorrenza di un identificatore e può essere applicato più volte. Il compilatore farà la sua solita cosa quando risolverà gli identificatori, iniziando dall'ambito locale e andando verso l'esterno. Quando trova qualcosa e l'operatore viene utilizzato, ignora il risultato e continua a cercare.
Considera questo esempio di pseudo-codice:
foo = 1 // global
object bar {
foo = "member foo"
function bla() {
let foo = 2
// _ we are here
}
}
Nella posizione di destinazione, foo
fa riferimento alla variabile locale con valore 2
.
@foo
sarà il membro di tipo stringa (salta un'occorrenza)
@@foo
sarà il globale variabile con valore 1
(saltare due)
Le alternative in linguaggi come Java o C # sarebbero this.foo
per il membro e qualche immaginario global::foo
per l'immaginario globale. Il problema è che a) gli utenti devono imparare diverse parole chiave eb) gli utenti devono comprendere la struttura esatta degli ambiti (cosa fa this
fa riferimento a ecc.)
La vera domanda: è una cattiva idea, ci sono alcuni problemi gravi che non vedo?
O ci sono forse delle lingue che impiegano un operatore del genere che potrei esaminare?
Un po 'più di contesto che potrebbe essere rilevante:
- questo non è un linguaggio di programmazione generico
- è un mix di elementi testuali e visivi (pensa Excel), quindi è chiaro visivamente cosa è contenuto in cosa (e dove ci porteranno le occorrenze)
- tipizzazione statica, nessun ambito dinamico (valutazione in fase di compilazione)
- L'idea è che le persone "capiscano" che la loro cosa abbia lo stesso nome di una cosa diversa, ma non conoscono le parole magiche per riferirsi esplicitamente al contenitore di quella cosa.
- scrivendo
@foo
dove c'è solo unfoo
provocherà un errore
Aggiornamento: alcune osservazioni:
-
Ambiti lessicali: ho omesso di menzionarlo, ma l'operatore dovrebbe sfuggire a tutti gli ambiti lessicali quando viene utilizzato per primo. Se ci sono 3 variabili in 3 blocchi annidati, come loop o funzioni, non puoi usare
@
per affrontarli. È inteso solo per accedere a scope non lessicali (oggetti, ambito globale). Credo che gli ambiti lessicali siano ancora più difficili da comprendere per i principianti e quindi non capirebbero quanti% di% di co_de avrebbero bisogno di rivolgersi a un membro. -
Fragilità: come menziona John R. Strohm, l'introduzione di un nuovo
@
o la rimozione di uno da un oggetto interromperanno tutti i riferimenti a% esistentefoo
resp. il numero difoo
richiesto per indirizzarli cambierà. Questo è davvero un problema, ma non è questo il caso, ad es. C # pure? Considera questo esempio:
.
namespace foo {
class X {
public static int Value;
}
namespace bar {
class foo { }
class X {}
class Main {
public static int Value = global::foo.X.Value + 1;
}
}
}
Creando un nuovo @
gli utenti possono nascondere altri tipi e spazi dei nomi negli ambiti esterni. Il codice esistente si interromperà e dovrà essere aggiornato, anteponendo i nomi dei nomi dei nomi o class
se i namespace fossero nascosti.
Il punto è: questo problema esiste in linguaggi come C # e non causa problemi. Il problema è più grave con l'operatore global::
, perché la rimozione delle cose causerà anche il fallimento, mentre l'indirizzamento esplicito degli ambiti risolve il problema una volta per tutte. La mia argomentazione a riguardo è questa: quando devi aggiustare il codice quando aggiungi roba, ci si può aspettare che tu debba aggiustarlo anche quando rimuovi qualcosa.
Aggiornamento: Ho accettato la risposta di John perché sottolinea un problema che ritengo sia peggiore di quello che molti altri hanno menzionato (copiare il codice in una posizione diversa può alterare quali simboli vengono indirizzati). < br>
Il problema è che se un utente crea un nuovo simbolo @
in un livello, modifica i simboli foo
risolti in livelli nidificati. In altre parole, una modifica invisibile al codice che non è attualmente in corso di modifica. A mio avviso questo è peggio del problema del copia-incolla, in quanto almeno può essere trattato in quel preciso istante e mentre continua a passare inosservato, l'utente ha una maggiore possibilità di scoprirlo.