Jump to content

Recommended Posts

While going through the tutorials, I recently ran into a behavior which surprised me a little bit. Two tutorials in a row used the same variable name, and the initialized value from the old tutorial persisted when I began the new one. Hilarity ensued. 

Do variables in opusmodus (or in this case, maybe in the underlying lisp VM?) have scope? Is there a way to manage this? 

I can imagine scenarios where global scope would be attractive or useful, but I was (apparently) expecting some kind of file-local sandbox for variables. 

Anyway, I am just wondering and didn't find an answer already in the forums... Thanks! 

Link to comment
Share on other sites

or maybe another way to ask this question is: what is opmo's `setf` implementation doing behind the scenes? since a direct call to `setf` is the recommended style (no `defvar` or `let`), and since that is undefined in Common Lisp AFAICT, it would be nice to have explicit documentation of how this affects variable scope. 

Link to comment
Share on other sites

I am asking a general question about how the Opusmodus runtime environment is scoping variables, but if it helps:

 

;;;--------------------------------------------------------
;;; Stage 5. List Processing
;;;--------------------------------------------------------

...

(setf pitches (gen-repeat 5 '((c4 cs4 fs4 g4 c5))))
(setf transposed-pitches (pitch-transpose -24 pitches))
(setf lengths (span pitches '(e)))
(setf lengths-rests (length-weight lengths :weight '(3 1)))

...

 

My observation is that `pitches`, `transposed-pitches`, `lengths` and `lengths-rests` are now global, once evaluated. If I open an unrelated file, a new file in a new workspace inside of the Opusmodus editor and evaluate:
 

(princ pitches)


The contents of the "pitches" variable will be printed, although that variable was evaluated in a different file, in a different workspace. This indicates to me that "setf" is creating a dynamically-scoped (global) variable behind the scenes, which is available to all of Opusmodus all at once.

 

That's fine, of course, but it probably should be documented somewhere. I am coming from a primarily C++ background, some ECMAScript, some Lua, with virtually no Lisp, though, and I was surprised by this scoping behavior. The Common Lisp documentation indicates that calling `setf` without a `let` or a `defvar` is strictly speaking undefined, so if the runtime environment is doing something useful (like creating a global variable), it's important to know that. Because otherwise naive users will reuse variable names and may run into unexpected side effects (and needlessly report bugs as a result 🙂 )

Link to comment
Share on other sites

In Common Lisp, `SETF` is a general-purpose assignment macro used to assign values to a designated place, such as a variable. It can be used for all forms of assignment, whether storing into an ordinary variable or a generalized variable. The syntax of `SETF` does not evaluate its first argument, which is the name of the variable. The second argument, which is the value to which the variable is set, is evaluated. The value returned by `SETF` is the value to which it set the variable.

 

Comparatively, `DEFVAR` and `DEFPARAMETER` are used for defining variables, but with different implications and scopes. `DEFVAR` is used to establish a variable, but if the variable is already bound, redefining it with `DEFVAR` does nothing. `DEFPARAMETER`, on the other hand, always assigns a value to the variable, even if it is already bound. Both `DEFVAR` and `DEFPARAMETER` are typically used to define global variables, whereas `SETF` is used for assigning values to variables regardless of their scope.

 

The scope of variables defined by `DEFVAR` and `DEFPARAMETER` is global, meaning the variables are accessible throughout the program. In contrast, `SETF` can be used within any scope, including local scopes within functions or global scopes, depending on where it is used. The key difference lies in their purposes: `DEFVAR` and `DEFPARAMETER` are for variable declaration (with `DEFPARAMETER` forcefully initializing the variable), while `SETF` is used for assigning or changing the value of a variable, irrespective of its scope.

Link to comment
Share on other sites

3 minutes ago, Stephane Boussuge said:

The scope of variables defined by `DEFVAR` and `DEFPARAMETER` is global, meaning the variables are accessible throughout the program. In contrast, `SETF` can be used within any scope, including local scopes within functions or global scopes, depending on where it is used. The key difference lies in their purposes: `DEFVAR` and `DEFPARAMETER` are for variable declaration (with `DEFPARAMETER` forcefully initializing the variable), while `SETF` is used for assigning or changing the value of a variable, irrespective of its scope.


Thank you, that all makes sense and corresponds to the documentation I've found in my searches online. The only part confusing me, why I wrote this post, is that `SETF` in Opusmodus is doing more than assigning a value to a designated place: it is creating a designated place (my observation: globally) if one is not yet defined. Lisp apparently provides mechanisms like:

(LET (pitches (gen-repeat 5 '((c4 cs4 fs4 g4 c5)))
	... ; some stuff
)

if I need to control the scope of my variables, it seems.

Anyway, I'm just trying to learn OMN and ran into this behavior, and erroneously reported a bug and felt bad, but also curious. So I wanted a definitive explanation before doing too deep down the rabbit hole.

Link to comment
Share on other sites

SETF in Common Lisp is a macro used for assignment. The basic syntax of SETF is:

 

(setf place value)

 

Here, place represents the location where the value is to be stored, and value is the value to be stored.

 

Example:

(setf x 10) ; sets the variable x to 10.


In Common Lisp, when you use SETF for an assignment, the value assigned to the specified location (or "place") will remain there until it is explicitly changed or replaced with another value. The "place" in the SETF statement refers to a location in memory where the value is stored. This could be a variable, a slot in a structure or object, an element in an array, and so forth.

 

Once a value is assigned to a place using SETF, it stays associated with that place. If you want to change the value, you need to use another SETF statement (or another appropriate form) to assign a new value to the same place. Until such a change is made, the original value will persist in that location.

 

The LET form is used to create local variables and bind them to values within a specified block of code.

Link to comment
Share on other sites

I feel like you're not understanding my question, but I am probably not speaking the correct jargon for hardcore Lisp users, I apologize.

 

In Opusmodus, evaluating

(setf place value)

creates a global "place" if "place" is undefined. True or false?

 

That is the only explanation I can find for the fact that evaluating

(setf pitches (gen-repeat 5 '((c4 cs4 fs4 g4 c5))))

results in the creation of a "pitches" variable which is available in other contexts (files, workspaces).

 

I understand how setting a variable works, and I understand how values are associated with names. But variables (or "places") have scope in every programming language, and my question is about the scope of the automatically created "place" generated by the evaluation of SETF (which occurs if the "place doesn't already exist). Does that makes sense?

Link to comment
Share on other sites

The "automatically created place" you are referring to when using SETF on a non-existent name does not have a universally defined behavior in Common Lisp. The standard practice is to declare variables explicitly.

Link to comment
Share on other sites

Argh. That's also what I wrote above.

 

De facto, based on the published practice of Opusmodus as provided in the Tutorials and other educational materials, you are recommending using SETF on non-existent names. So what, in your opinion, is supposed to happen in that case? You do it all over the place, it is how you teach newcomers to use Opusmodus: you must have a clear idea of what is expected.

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

Terms of Use Privacy Policy