<bitbasher>
There really is nothing special about special variables is there? i have been testing to see what if anything is different .. but they seem to work just like global variables whose names do not start with $ .. can anyone tell me anything different?
<bitbasher>
or .. maybe they were a way to get values down to modules several levels of call from global level before the 2015 version that allowed locals to be assigned in any local scope?
<bitbasher>
if anyone know the history i will show it in the docs, but for now i will document that specials are not .. well, special
<teepee>
"normal" variables are lexically scoped = where they are written in code. "special" variables are dynamically scoped "in the chain of calling"
kintel has joined #openscad
<kintel>
$special=1;
<kintel>
normal=1;
<kintel>
a();
<kintel>
let ($special=2, normal=2) a();
<kintel>
module a() { echo($special, normal); }
kintel has quit [Quit: My Mac has gone to sleep. ZZZzzz…]
mwette has joined #openscad
<mwette>
"normal variables are lexically scoped, special variables are dynamically scoped" is highly valueable info, but I didn't find it in the manual. Should I create an issue?
<bitbasher>
no need for an issue .. i just this evening simplified the description of specials so if there is something needed i will add it back in immediately .. but here is the thing
<teepee>
try to not break the main page too much though. the link to "special variables" currently goes nowhere
<bitbasher>
my experiements show that in the dev snapshot user defined specials, like $myspecial = 12; work exactly like normal variables defined by assignment at the global scope
<bitbasher>
ah .. a broken link .. i can fix that
<teepee>
no, they don't as the example from kintel ^ shows
<teepee>
if you have *only* global variables and no other assignements at all, then they are indeed identical
<bitbasher>
actually i dont think kintels example does show a difference .. setting any variable as second time makes ALL uses of that variable use the _last_ value assigned
<teepee>
and that also only applies when talking about a single main script with no use<>
<teepee>
well, the result is: 1, 1 and 2, 1
<teepee>
I would think that's a difference
<bitbasher>
oh .. is a special set in a Main program visible in an included script?
<teepee>
yes, when it's in the call chain of functions/modules
<teepee>
that's how $fn affects also geometry modules imported via use<>
<teepee>
(unless those modules hard code a fixed value)
<bitbasher>
umm well i suspect some diff reason for pre-defined specials .. but okay
<bitbasher>
in this code $xxx = "xxx"; if(true) { $xxx="yyy"; echo($xxx); } echo($xxx);
<bitbasher>
the result is "yyy" from the inner scope and "xxx" in the global
<teepee>
sure, if you overwrite it directly in the same scope
<bitbasher>
gives "yyy" and then "zzz" .. same behaviour as any global
<teepee>
yes, that is behavior that has nothing to do with scoping
<teepee>
it's just that overwriting a variable in the same scope appears as it would be assigned in the first place
<bitbasher>
but when i assign a new value to $xxx in the inner scope it is only changed locally
<teepee>
so that zzz effectively jumps to the place where the xxx was assigned
<teepee>
you can *never* redefine a variable ever
<teepee>
if you have 2 assignement statements, you'll get the 2nd one in place of the first one
<bitbasher>
ah .. well .. i see as the last assignment to any variable is compiled to be its value wherever used .. at a particular level of scope
<teepee>
if you open a new scope, you create a new variable shadowing the one in outer scopes, which is why those in the outer scope do not change
<bitbasher>
right .. so assigning a value to a name in an inner scope .. regular or special .. is a local variable that hides that global one .. correct .. and so there is no diff between a regular and special variable .. or am i still missing something?
<bitbasher>
what i see is both types of var work exactly the same
<teepee>
did you try kintels example?
<bitbasher>
yes .. i have it in scad now
<teepee>
well, that does everything identical with the 2 variables but the result is different for the last line
<bitbasher>
the let() is defining a local variable called $special with value 2 .. a is then called in that scope so i prints 2,1
<JordanBrown>
Emphasis on the "called in" part.
<teepee>
yes, and normal is also set to 2
<teepee>
but for lexical scoping a() sees the global variable
<mwette>
You can introduce new bindings in modules, functions, let and (used) files?
<bitbasher>
so this is kintels example using a dummy if to define an inner scope
<teepee>
due to dynamic scope a() sees 2 as value as it travles up the stack to find the value and the next upper level on the stack is the assignment in let()
<bitbasher>
normal = 2 is in the local scope and so is not visible inside a() so a() prints the global value of normal=1 .. yep i see that
<teepee>
yes, it does not matter if that's let() or if () {}
<teepee>
the point is normal is lexical as in "look at the code as written" and dynamic "look at the current stack at the time you want to know the value"
<teepee>
mwette: functions no, as those are only one expression (I think?)
<bitbasher>
you can still use let() in a function to set values in a local scope
<teepee>
or maybe I misunderstand the question :)
<JordanBrown>
Don't mess around with let() until you understand the behavior without it. Not that it's weird, but it confuses the issue.
<JordanBrown>
teepee yes, functions are exactly one expression. Possibly a very complicated expression.
<bitbasher>
i have been doing a LOT of experiements to check my understanding of scope in this wierdo function language (sorry) and i do not see that special variables are special .. it looks like they work like any other variable
<teepee>
true, with let and other function calls, you can get many assignments :)
<JordanBrown>
If they behave the same, why does the example above give different results for the two calls?
<bitbasher>
a globally defined special can be obscured by assigning something to it in a local scope .. but leave that scope and the global value is back .. just like for a normal variable
<JordanBrown>
Well, yes, they are *related*.
<JordanBrown>
Neither one of them behaves like a "variable" in most languages.
<teepee>
you did not get back the global assignment when it printed 2 for $special
<teepee>
that is exactly where it's different
<bitbasher>
the two calls are to the a() module .. which uses the global for "normal " in all cases but sees the local redefinition of $special in the inner scope
<JordanBrown>
But why does it see the redefinition of $special, but not the redefinition of normal?
<JordanBrown>
That is precisely the difference between the two.
<bitbasher>
because normal=2 is a local assignment .. does not touch the global normal=1
<JordanBrown>
But why does it see $special=2?
<bitbasher>
x-ray glasses .. that is how ! ah ha .. i figured it out !
<bitbasher>
but seriously
<JordanBrown>
And you're right, by the way, that the setting of normal inside the "if" has exactly zero effect on a().
<teepee>
I suppose x-ray variables is not much worse than special variables ;-)
<JordanBrown>
Because the a() module is not inside that scope.
<teepee>
in static code wise point of view
<bitbasher>
yes .. i am changing every ref to "special variable" to "x-ray glasses equipped variables"
<JordanBrown>
But special variables are scoped by the call stack, *not* by the layout of the program, and there the innermost setting of $special is the one inside the if.
<bitbasher>
yep .. doing that now ...
<bitbasher>
no more calling anything special in this language .. that word is now removed from all dictionaries
<bitbasher>
the S word is gone
<JordanBrown>
Do you understand the scoping of normal variables?
<bitbasher>
oh yeah .. been dealing with scope issues since BASIC and Assembly were the Hot Languages
<JordanBrown>
So you understand why x=1; if (true) { x=2; } echo(x); yields 1?
<bitbasher>
the echo is in the global scope .. sure
<bitbasher>
the anon scope is .. well it does not create an inner scope .. which noticed in the docs and tested .. it really does not do anything .. but i feel it should create an anon inner scope .. which is another story for another time
<JordanBrown>
You have a weirdo case in there. "anonymous" scopes, braces with no operator in front of them, do not create scopes.
<JordanBrown>
So do I, but there are some (in my opinion weak) arguments against it.
<bitbasher>
yep .. and it was already documented
<JordanBrown>
(What, you might ask? Braces allow collapsing in the editor.)
<JordanBrown>
It's probably simplest if you just never use anonymous scopes.
<bitbasher>
ah .. well yes, there is that but .. mehh .. just .. mehh
<bitbasher>
okay .. so dynamic scope .. i dont like that term either .. scope does not change with .. the tide or anything
<JordanBrown>
So if we slap an if(true) in front of your anonymous scope so that it's a real scope...
<JordanBrown>
You should get 1,1; 2,1; 1,1
<JordanBrown>
The setting of a special variable applies to the current scope *and everything called from the current scope*.
<bitbasher>
but i get that $special can be assigned a new value inside a module .. actually in an inner scope created by any block .. and in that block set that special to a different value which is held on the call stack at run-time .. not the compiled storage location .. is that close to the truth?
<JordanBrown>
While the setting of a normal variable applies to the current scope and all scopes physically inside it.
<JordanBrown>
Sort of?
<bitbasher>
yes, that dummy if() gives the 1,1 2,1 1,1 expected result
<JordanBrown>
Yes, I suppose that you could say that normal variables can always be assigned static storage locations.
<bitbasher>
and that they hold the LAST value assigned .
<JordanBrown>
Deepest, is a better way to think of it.
<bitbasher>
meaning .. the value assigned in the last assignment statement compiled with a given variable name as target
<JordanBrown>
Deepest, in terms of nesting of scopes.
<bitbasher>
to be really .. really pedantic
<JordanBrown>
"last" implies chronology, and that's *not* true.
<JordanBrown>
a = 1; if(true) { a = 2; } echo(a);
<JordanBrown>
in some sense when you get to the echo the a=2 is the 'last" assignment, but it is *not* the one that applies.
<bitbasher>
i am using "last" in the sense of "order of statements" as they are compiled .. not in the sense of time
<JordanBrown>
As long as you remember to pop the stack when you exit from a scope.
<JordanBrown>
But yes, if you want to think of it that way, normal variables are compile-time scoped.
<JordanBrown>
special variables are run-time scoped.
<JordanBrown>
(That's not how it actually works in the implementation, but it's not a silly mental model.)
<bitbasher>
ah .. we have to also say .. last assignment compiled at the global level .. as any assignment in an inner scope does not affect the global storage allocation
<bitbasher>
the results of this led me to my way of thinking about this
<JordanBrown>
There's nothing special about "global"; it's just the top level scope.
<JordanBrown>
But I have a local interruption; back in a few minutes.
<bitbasher>
i dont think it is correct to say specials are run-time scoped .. setting a new value in an inner scope changes its "global" value .. which is not literally correct .. but in the sense that using the special in a module .. and then calling that module in the inner scope means the inner scope value is used .. sort of like you changed the global value that the module is referring to temporarily .. during the time the code creating the i
califax has quit [Ping timeout: 244 seconds]
<bitbasher>
i am now going to fix that broken link and redo the description of specials
califax has joined #openscad
<bitbasher>
so i will see if you have more to tell me .. and thx by the way for talking me through all this
<JordanBrown>
back
<JordanBrown>
No, changing a new value in an inner scope does *not* change the global value of the special variable.
<JordanBrown>
The setting of a special variable is passed to everything called from that scope, and evaporates when you exit from the scope.
<bitbasher>
yep .. i see that now ..
<JordanBrown>
Nothing *ever* changes the value of a variable, of either kind.
<JordanBrown>
All you can do is create new variables with the same name, that hide the outer variables, and you can exit from scopes and lose the inner variables and so expose the outer variables.
<bitbasher>
but .. it LOOKs like an assignment to a special in an inner scope is changing its value
<JordanBrown>
Only if you don't think in terms of the call stack.
<JordanBrown>
That's the difference: normal variables are scoped by the layout of the program, while special variables are scoped by the call stack.
<bitbasher>
which is a very weird way to think about scope
<bitbasher>
but .. i do get it now
<JordanBrown>
What, scoping by call stack? I don't *think* it's all that weird... or at least this isn't the first language that I've seen do it.
<JordanBrown>
What's unusual is that there's no declaration involved, that *every* assignment creates a new variable.
<bitbasher>
no ? i have not come across any language that let variables defined in a global scope be used in a function but still could be assigned an effectively local value created in an inner scope of some other bit of code
<JordanBrown>
Dynamic-scope variables are not present in most modern languages.
<JordanBrown>
One that I happen to know of (because I implemented local variables) is dBASE.
<bitbasher>
oh .. Jordan .. change of topic .. i was playing around trying to create an object with named members the other day .. could not do it
<JordanBrown>
But I think some LISP variables are that way.
<JordanBrown>
What do you mean by "with named members"?
<bitbasher>
i was looking for objects created by any of the built-in functions .. the textinfo returns an object
<bitbasher>
do you know of any others?
<JordanBrown>
Unless you are running a *bleeding* edge build - I don't know if there's even a nightly new enough - there's no way to create an object.
<JordanBrown>
There was a function integrated in the last day or two that lets you create them.
<bitbasher>
oi oi .. you were on the dBase team .. nice bit of history there
<JordanBrown>
dBASE III.
<JordanBrown>
III+ too; I don't remember if it released before or after I left.
<bitbasher>
loved and hated that language in equal measure ..
<JordanBrown>
As well you should.
<bitbasher>
LOL ..
<JordanBrown>
Offhand, I created local variables, dates, and the label generator.
<JordanBrown>
And I did a lot of work on the abortive UNIX port.
<bitbasher>
i am planning to document any existing objects .. but they are not called out in the docs .. except for textinfo()
<JordanBrown>
Until the last few days, there have only been three ways to create an object.
<JordanBrown>
textmetrics(), fontmetrics(), and import("whatever.json")
<bitbasher>
brave trying to move dBase to Unix in the face of the DBs already on those platforms
<JordanBrown>
One thing that DB people never got was that dBASE was only sort of a DBMS.
<bitbasher>
ah ha.. the json import does it too! i missed that one
<JordanBrown>
It was really an application development environment.
<JordanBrown>
And textmetrics() and fontmetrics() are documents.
<JordanBrown>
I *hate* that people have moved away from "links are always blue and underlined".
<bitbasher>
sorry .. and i may wind up absorbing that Data Types etc page into the General one
<JordanBrown>
So, anyhow, I believe that (except for the changes in the last few days) everything there is to know about objects is documented.
<JordanBrown>
That was certainly my intent when I wrote that text :-)
<bitbasher>
oh? links in our docs so the blue underline thing no?
<JordanBrown>
I don't quite understand that.
<bitbasher>
ok .. good to know
<bitbasher>
you comment about hating links that are not shown in blue + underline
<JordanBrown>
I see that Wikibooks underlines the links when you hover, which is better than nothing, but you still have to know when blue text is a link and when it's just ... blue text.
<bitbasher>
our docs still do links correctly yes?
<JordanBrown>
Not by my standards. But as I said, people have moved away from the old ways.
<bitbasher>
ah well .. blue text has always been a prob that way
<bitbasher>
BTW .. i am moving to use transclusion to bring the new, separate pages of info on specific topics into pages where related things will be visible together
<JordanBrown>
Just be careful - duplication, even apparent duplication, is a bad thing.
<JordanBrown>
The object() function was merged on July 10 at 20:48 PDT.
<bitbasher>
and i would be grateful if you could use the discussion pages to pass on suggestions of what should go where .. and any mistakes i have managed to make
<JordanBrown>
So July 11 at 03:48 UTC, if I'm doing my math right.
<bitbasher>
pacific time is 9 hours from me here in Gent
<JordanBrown>
about 44 hours ago.
<bitbasher>
ah .. that new function you mentioned .. ok then . time to update my dev snapshot install
<JordanBrown>
there's a July 11 build, so *maybe* it has it.
<JordanBrown>
object(name=value, name=value, ...) yields an object with those names and values.
<JordanBrown>
object([[nameexpr, value], ...]) yields an object with those names and values.
<JordanBrown>
object(o1) yields an object with the same properties as o1
<JordanBrown>
you can combine those, so object(o1, a=123) yields a copy of o1, but with "a" set to 123.
<JordanBrown>
And object(o1, [[namexpr], ...]) removes a member from the object being constructed, so yields a copy of o1 but without the specified member.
<bitbasher>
clecver stuff! .. and can those named values be lambdas? in which case we have methods
<JordanBrown>
What *precisely* do you mean by a lambda?
<JordanBrown>
If you mean a function reference, yes, of course.
<JordanBrown>
But we are still missing a key piece for implementing methods: the function has no way to know which object it came from.
<bitbasher>
an anonymous function assigned to be an element of an array or member of an object