Cosa fa `setq-local` e quando dovrei usarlo?


16

Non sono abbastanza chiaro su tutte le variazioni delle variabili buffer-local, anche dopo aver letto tutti i documenti e un sacco di post qui su SX.

Ecco un riassunto delle mie comprensioni:

(defvar foo ..)dichiara una variabile dinamica per il file. Ma la variabile è (1) non nota ad altri file a meno che non includano anche defvar un'istruzione e (2) la variabile abbia un ambito globale, non un buffer locale.

(make-variable-buffer-local foo)dopo quanto defvarsopra dice al compilatore e a tutti gli altri che la variabile foo deve essere trattata come buffer-local ovunque sia impostata, quando è impostata. Quindi questo modello è un buon stile per dichiarare una variabile buffer-local, mettendo entrambe le istruzioni back-to-back nel file.

(defvar xxx ...)                    ;declare xxx with global scope
(make-variable-buffer-local 'xxx)   ;but now make it buffer-local everywhere

Per comodità, il (defvar-local xxx ...)modulo può essere utilizzato come una riga, al posto delle due righe sopra:

(defvar-local xxx ...)       ;make xxx buffer local everywhere

Una volta dichiarata come sopra, la variabile xxx può essere utilizzata come qualsiasi altra variabile nelle istruzioni setq.

Se voglio solo avere una singola istanza di una variabile buffer-local che è già una variabile dinamica globale, userò le seguenti dichiarazioni. Il primo dichiara la variabile dinamica di portata globale e la seconda istruzione crea solo un'istanza di una versione buffer-local di quella variabile, nel buffer corrente:

(defvar xxx ...)             ;declare xxx with global scope
(make-local-variable 'xxx)   ;make xxx local in this buffer only

Ora per le mie domande esplicite (tutte le precedenti domande erano implicite sulla mia comprensione corretta).

Quando si imposta il valore delle variabili, posso usare setqo setq-local. Quando dovrebbe setq-localessere usato? Perché?

Cosa succede se utilizzo setq-localsu var-local buffer o su non-buffer local?

È setq-localrichiesto per una defvar-localvariabile dichiarata?

Sarà setq-localsu un normale defvarvariabile dichiarata trasformarlo in una variabile buffer locale? (In altre parole, è in setq-localqualche modo l'equivalente di una (make-variable-local xxx)dichiarazione?


Grazie per il lavoro extra Scott. Da qui in poi inserirò i backquotes extra.
Kevin

2
(setq-local VAR VALUE)è solo una scorciatoia per (set (make-local-variable VAR) VALUE), che era (ed è tuttora) un linguaggio comune.
Estratto il

Risposte:


18

La maggior parte dei tuoi presupposti sono vicini. Ne citerò alcuni più tardi. Ma prima la domanda principale.

Il modulo setq-localè semplicemente una comodità, è lo stesso che fare make-local-variableseguito da setq. Se avessi fatto un C-h f setq-localper vedere la documentazione e fatto clic sulla fonte, potresti averlo visto. È così che ho verificato la mia prima impressione. Il codice è un po 'oscuro, dal momento che si sta ottimizzando su cose come il fatto che in make-local-variablerealtà restituisce la variabile stessa. L'utilizzo setq-localè un modo per evidenziare la localizzazione in alcuni codici, in modo che altri sappiano che il codice non può essere riprodotto con il valore globale della variabile. Non è necessario utilizzarlo per accedere alle variabili locali. Ogni variabile può essere resa buffer-locale e ciò influirà su tutto il codice che tocca la variabile (tranne se fa di tutto per ottenere la copia globale setq-defaulto simile).

Questa è la risposta principale. Ora, ci sono alcune cose nel tuo background che sono un po 'fuori. Dato che me l'hai chiesto, mi occuperò di alcune cose.

Il primo è "non noto ad altri file". Questo non è proprio vero. Qualsiasi codice può fare riferimento a qualsiasi variabile globale (ecco perché sono chiamati "globali") senza includere defvar(e lo C-h f defvardice). In effetti, dovrebbe esserci solo undefvar elemento principale (con docstring e valore predefinito) per ogni variabile globale. A defvarcon solo il nome della variabile può essere utilizzato per sopprimere un avviso del compilatore di byte. Emacs utilizza solo il valore dal primo che vede¹ e il docstring dall'ultimo. Se ci sono più defvars con value / docstring possono confondere le persone che leggono il codice. E l'ordine del caricamento dei file sarà importante.

Alcune variabili sono intese per essere utilizzate solo come buffer-local e quelle che usano defvar-local(o le due parti defvar/ per make-variable-buffer-localcui è abbreviata, principalmente nel codice precedente prima che fosse aggiunta la forma breve). Questo lo rende un buffer locale in tutti i buffer. Per alcune variabili, il loro uso principale non è buffer-local, ma per qualche motivo potresti volere che un buffer abbia un valore diverso. Questo è quando lo usi make-local-variable, di solito in qualche codice di configurazione del buffer quasi mai subito dopo un defvar.

E in generale, le defvarforme hanno due scopi . Uno è avere della documentazione, in modo che C-h vpossa essere utilizzato da altri per sapere a cosa serve la variabile. Il secondo è dichiarare un valore "predefinito", in modo che la variabile sia sempre impostata. La dichiarazione del valore predefinito influisce solo sull'istanza globale (o predefinita) di una variabile e viene utilizzata solo se tale istanza non è già impostata su qualcosa. Ciò significa che se si setqaggiunge una variabile e quindi si include il file con defvar(es. Attraverso a require), defvar non cambierà il valore.

¹ Più precisamente, defvarnon modifica il valore della variabile se è già impostata (imposta comunque la docstring); ciò significa che il file init dell'utente può eseguire (setq some-variable)prima che un pacchetto venga caricato per sovrascrivere il valore predefinito del pacchetto.


1
Grazie per la risposta molto chiara, aiuta molto. Quando ho usato la frase "non nota ad altri file", pensavo agli avvertimenti sulle variabili libere perché quegli altri file penseranno che la variabile sia libera a meno che non aggiunga anche una defvar. Mi piace la tua affermazione che set-localdice ai lettori che è stata impostata una var locale. Tutto ciò che posso fare per migliorare la leggibilità del mio codice è buono! PS. Proverò a fare clic sulla fonte più spesso; al mio attuale livello di sviluppo, spesso non arriva davvero alla semantica ... :-)
Kevin

1
"dovrebbe essercene solo uno defvarper ogni variabile globale" non è strettamente corretto - ci sono situazioni in cui (defvar VARNAME) senza un valore dovrebbe essere dichiarato, indipendentemente dalla definizione corretta (con valore iniziale e idealmente una stringa) di quel VARNAME.
phils,

2
Nota anche che setq-locale defvar-localsono stati introdotti solo in Emacs 24.3.
phils,

1
@phils, potresti per favore identificare le situazioni di cui parli, dove (defvar varname)dovrebbero essere dichiarate senza valore? Penso che sia quello che ha suggerito Drew in un altro thread quando mi chiedevo come eliminare gli avvisi variabili gratuiti nei miei file per i globali che avevo dichiarato altrove. Lo faccio ora. È questa la situazione di cui parli?
Kevin,

1
Evitare gli avvisi di compilazione di byte è un motivo, sì (vedi C-h i g (elisp) Warning Tips). L'altro è per le biblioteche che usano il legame lessicale, per assicurare (se necessario) che una variabile sia legata dinamicamente piuttosto che legalmente.
phils,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.