What happened to booleans?

classic Classic list List threaded Threaded
83 messages Options
12345
Reply | Threaded
Open this post in threaded view
|

Re: What happened to booleans?

adrianv
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
>> >> >>
>> >> >> >
>> >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>> >> >>
>> >> >>
>> >> >>
>> >> >>
>> >> >>
>> >> >> --
>> >> >> Sent from: http://forum.openscad.org/
>> >> >>
>> >> >> _______________________________________________
>> >> >> OpenSCAD mailing list
>> >> >>
>> >>
>> >> > Discuss@.openscad
>> >>
>> >> >>
>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>> >> >>
>> >> >
>> >> > _______________________________________________
>> >> > OpenSCAD mailing list
>> >>
>> >> > Discuss@.openscad
>> >>
>> >> >
>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>> >>
>> >>
>> >>
>> >>
>> >>
>> >> --
>> >> Sent from: http://forum.openscad.org/
>> >>
>> >> _______________________________________________
>> >> OpenSCAD mailing list
>> >>
>>
>> > Discuss@.openscad
>>
>> >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>> >>
>> >
>> > _______________________________________________
>> > OpenSCAD mailing list
>>
>> > Discuss@.openscad
>>
>> > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>>
>>
>>
>>
>>
>> --
>> Sent from: http://forum.openscad.org/
>>
>> _______________________________________________
>> OpenSCAD mailing list
>>

> Discuss@.openscad

>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>>
>
> _______________________________________________
> OpenSCAD mailing list

> Discuss@.openscad

> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org





--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: What happened to booleans?

doug.moen
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.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: What happened to booleans?

adrianv
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/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
12345