So you're saying that
foo=sin;
creates a function literal but
sin=12;
foo=sin;
creates a number? Or maybe I misunderstand. Do other people think this is
a good idea? This breaks OpenSCAD's general system of having different
namespaces for variables and functions. Given that variables and functions
have their own namespace I should be able to introduce a "sin" variable
without changing how my code interacts with the function namespace.
Also, it should be possible to do the same thing with a user defined
function, that is, I should be able to have a library define
function cosh(x) =(exp(x)+exp(-x))/2;
then then I should be able to set
foo = cosh
in the same way that I could set
foo = cos,
converting a defined function (whether builtin or not) into a function
literal. There shouldn't be a different syntax required for non built-ins
than for built-ins. A library should be able to define cosh and a user not
have to know that it is not a built-in.
thehans wrote
The difference is that undef is an already established builtin constant
value, but sin is not.
x = sin;
WARNING: Ignoring unknown variable 'sin', in file , line 1.
If builtin functions were treated as literals, then that would be fine
with
no warning, and x would then hold a FunctionType value.
The user would of course be free to assign a value to their own variable
named "sin", and this would shadow our hypothetical builtin function
literal of the same name.
It would be a weird thing for the user to do, but not ambiguous.
On Fri, Jul 31, 2020 at 6:35 PM adrianv <
avm4@
> wrote:
I hadn't really thought about how function literals might be involved
here.
But I'm a little puzzled. Suppose builtin functions can be treated as
literals as shown below. Then
foo = sin
is ambiguous about whether I mean the function "sin" or the variable
"sin".
I would think that if you want to make regular functions (and built-ins)
available as literals---which is a really good idea because otherwise it
creates a confusing situation where some functions need to be redefined
as
function literals for convenience---you should do something like what
MATLAB
does and create a syntax for it. In MATLAB you create a function literal
(they call them handles) from (any) function using "@". So in MATLAB
foo = @sin
assigns a function literal into foo. And the call
foo(@sin,@cos)
passes two function literals into the function foo. Given how namespaces
work in OpenSCAD there's no way to assign a pre-existing function to a
variable or pass functions as literals without a new syntax that
"converts"
the function into a literal.
But my point is that
foo=undef
is not any more ambiguous than
foo=sin
so it's not a problem that has to do with undef. So I still don't see
any
issue with using the functional form I proposed.
foo = undef; // Plain undef without text
foo = undef("reason"); // undef with text
foo = @undef; // or whatever new syntax.... the undef
function...though
why would you ever want that?
Have I missed something?
thehans wrote
As Doug points out, the situation is more complicated if you account
for
function literals, which already exist as an experimental feature.
It's not necessarily an issue at the moment, but If we ever decided to
make
builtin functions accessible as literals (personally i would like to
see
this), then writing: foo = undef; would be ambiguous whether you want
the
function literal value or the actual undef literal.
On Fri, Jul 31, 2020 at 5:29 PM adrianv <
avm4@
> wrote:
What is confusing about calling undef() like a function? You say we
don't
want to "mix up" the undef literal with an undef constructor, but
what's
the
difference really between
undef
and
undef("some reason text")
Isn't the first one basically the same as the second one only with the
argument missing, in some sense? What's the problem or consequence of
"mixing up" these two things? When there's no string associated with
an
undef then what is there? Empty string? Another undef? It's a bit
unclear what the advantage is of not having a string. Shouldn't there
always be one? (undef: "list index out of bounds", undef: "variable
not
set", undef: "mismatched argument types for +".) It seems like you'd
want
to encourage users to supply the string any time they make an
assignment.
I guess there's the question of what it means if you just write
"foo=undef",
as in that case there's no string. The string could be "direct
assignment"
or something like that.
To me it seems like doing
foo = undef
but
foo = undefined("some reason")
is more confusing because now I have to remember when to use undef and
when
to use undefined. It looks like undef is already illegal as a
function
name, so it wouldn't break any code, whereas undefined() is currently
a
valid function, so using that could break code.
thehans wrote
No I haven't added any mechanism to query or set undefined strings
programmatically from scripts, since I felt like that needed some
more
thought and planning around the interface, and wanted to limit this
PR
to
only the least contentious changes.
Adding either of those should be fairly quick and simple to
implement
though.
For displaying the string, i considered that echo() and str() could
possibly automatically show the undef strings if any. But this
might
end
up with more verbose messages than people would like for general
cases.
Also as far as I know, echo() and str() generally work in such a way
where
you could copy/paste output back into a script and it should be
parsed
into
the same literal values. So doing something like that should
probably require that we first lock in how the string would be set
programmatically (see below).
Having assert() handle undef as a special case might be one good way
to
inspect for reason strings though.
Another possibility is that the reason string could be a "member
lookup"
on
undef types, so e.g. ( some_undef_value.reason ) could return a
string.
But then should an undef without any string return undef for that as
well?(its undefs all the way down!)
And would ".reason" on a non-undef type also be undef, or throw an
actual
error?
For setting the string, I don't think calling undef() like a
function
is
a
good idea, since we don't want to mix up the default literal "undef"
identifier with a new builtin function(constructor basically)
identifier
of
the same name. But perhaps a function named undefined() would be
fine,
for
example.
On Fri, Jul 31, 2020 at 5:36 AM adrianv <
avm4@
> wrote:
Another question: is there a way to create an undef and associate
a
reason,
so for example
undef("line_intersection: lines did not intersect")
JordanBrown wrote
On 7/30/2020 9:24 PM, Hans L wrote:
I've now implemented the capability for undef types to carry a
reason
string.
Cool.
So if your program has an undef in its hands, is there a
straightforward
way to say "what is the reason for this undef"?
I don't know whether it's necessary to have a way to retrieve
the
reason, or just a way to say "hey, I don't want an undef, this is
an
error, report the error with the reason for the undef".
One really simple mechanism might be to have assert(undef) report
the
reason for the undef.
That would be an exception to the general rule that undef is OK
in
a
boolean context, but then again undef is false in a boolean
context
and
assert(false) is an error, so it's not stretching the rule very
much.
OpenSCAD mailing list
Discuss@.openscad
Discuss@.openscad
OpenSCAD mailing list
Discuss@.openscad
Discuss@.openscad
Discuss@.openscad
Discuss@.openscad
Discuss@.openscad
--
Sent from: http://forum.openscad.org/
On Fri, Jul 31, 2020, at 8:51 PM, adrianv wrote:
So you're saying that
foo=sin;
creates a function literal but
sin=12;
foo=sin;
creates a number? Or maybe I misunderstand. Do other people think this is
a good idea?
If you are coming to OpenSCAD after having first learned another programming language,
like Javascript or Python, then the above is exactly what you would expect.
The 'sin' function is a system wide global, from the outermost scope.
A variable definition like
sin=12;
creates a more local variable at the file or module scope.
And now after
foo=sin;
you would naturally expect that the new variable 'foo' contains the value
of the local variable 'sin'.
Try both of these in Python, and that's the behaviour you get.
As for how it could be implemented, I wrote a proposal for this a few years ago:
https://github.com/doug-moen/openscad2/blob/master/OpenSCADbis.md
With the addition of function literals, named functions can be in either the
variable namespace or the function namespace. In the above proposal, built in
functions like 'sin' are defined in both the function and the variable namespace.
So there is a builtin variable called 'sin'.
So the statement
foo = sin;
defines 'foo' in terms of the sin variable.
This breaks OpenSCAD's general system of having different
namespaces for variables and functions. Given that variables and functions
have their own namespace I should be able to introduce a "sin" variable
without changing how my code interacts with the function namespace.
Well, you can also say that the introduction of function literals "breaks"
OpenSCAD's system of segregating functions and variables into different namespaces,
because now you are free to adopt a coding style where all user defined functions
are in the variable namespace. The proposal I wrote was intended to make this new
coding style more comfortable, without breaking backward compatibility with
existing scripts. This "new" coding style is the way people expect to code if they
have prior exposure to another programming language.
Also, it should be possible to do the same thing with a user defined
function, that is, I should be able to have a library define
function cosh(x) =(exp(x)+exp(-x))/2;
then then I should be able to set
foo = cosh
in the same way that I could set
foo = cos,
converting a defined function (whether builtin or not) into a function
literal. There shouldn't be a different syntax required for non built-ins
than for built-ins. A library should be able to define cosh and a user not
have to know that it is not a built-in.
In the original proposal, if the library uses the new function definition syntax:
cosh(x) = (exp(x) + exp(-x)) / 2;
(omitting the 'function' keyword), then the function 'cosh' is defined
in both the function and variable namespace, and everything works the
way you said.
However, if the library uses the old function definition syntax,
then the function will only be defined in the function namespace,
as seems required for backward compatibility.
More generally, even without the details of my proposal, it's the case that
once function literals are in the language, it is no longer guaranteed that
libraries will define functions only in the function namespace.
doug.moen wrote
On Fri, Jul 31, 2020, at 8:51 PM, adrianv wrote:
So you're saying that
foo=sin;
creates a function literal but
sin=12;
foo=sin;
creates a number? Or maybe I misunderstand. Do other people think this
is
a good idea?
If you are coming to OpenSCAD after having first learned another
programming language,
like Javascript or Python, then the above is exactly what you would
expect.
The 'sin' function is a system wide global, from the outermost scope.
A variable definition like
sin=12;
creates a more local variable at the file or module scope.
And now after
foo=sin;
you would naturally expect that the new variable 'foo' contains the value
of the local variable 'sin'.
Try both of these in Python, and that's the behaviour you get.
It's also the behavior in OpenSCAD, is it not? The only thing that's weird
about OpenSCAD in this regard is that variables and functions have separate
namespaces.
With the addition of function literals, named functions can be in either
the
variable namespace or the function namespace. In the above proposal, built
in
functions like 'sin' are defined in both the function and the variable
namespace.
So there is a builtin variable called 'sin'.
So the statement
foo = sin;
defines 'foo' in terms of the sin variable.
Given the obsession with backwards compatibility I assumed a backwards
compatible approach that matched up with how things generally work in
OpenSCAD. But I can see that I hadn't thought this through carefully.
When I first read the proposal my immediate reaction was that it would more
or less require me to define all my functions in the new style because
otherwise there's a lack of flexibility. That seemed odd. And of course it
might break code if I have variables that share a name with a function.
But it sounds like you're saying that was actually the intent, that people
might switch to the new style, and work with a single name space for
functions and variables.
This breaks OpenSCAD's general system of having different
namespaces for variables and functions. Given that variables and
functions
have their own namespace I should be able to introduce a "sin" variable
without changing how my code interacts with the function namespace.
Well, you can also say that the introduction of function literals "breaks"
OpenSCAD's system of segregating functions and variables into different
namespaces,
because now you are free to adopt a coding style where all user defined
functions
are in the variable namespace. The proposal I wrote was intended to make
this new
coding style more comfortable, without breaking backward compatibility
with
existing scripts. This "new" coding style is the way people expect to code
if they
have prior exposure to another programming language.
However, if the library uses the old function definition syntax,
then the function will only be defined in the function namespace,
as seems required for backward compatibility.
More generally, even without the details of my proposal, it's the case
that
once function literals are in the language, it is no longer guaranteed
that
libraries will define functions only in the function namespace.
For libraries to define things in the variable namespace they have to be
included instead of used. Also libraries that are used can't define any
variables because this leads to performance issues. So it's a little
unclear what might happen with libraries written to use function literals.
I hadn't thought about it being "no longer guaranteed that libraries will
define functions only in the function namespace" but it's certainly true.
So the introduction of function literals represents a more fundamental
change than I realized.
Are there plans to provide a way to check the arguments that a function
requires? That is, if I write a function that takes as an argument a
function of two variables, can I somehow check that the function I've been
given accepts two variables?
Are there plans to merge the module and variable namespace as well? Because
the library I work on has tons of function/modules where the function form
returns something and the module form makes the corresponding geometry.
Anyways, with your clarification the problem with my undef functional form
proposal is clear. But it seems better to have a language structure than a
magic function with an inconsistent name that constructs the undef with its
descriptive string. I'm not sure what that might look like, though. Or
the concerns about introducing new syntax.
--
Sent from: http://forum.openscad.org/