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
I think you're missing the point.  The current undef behavior may allow me to
HANDLE errors but it does not enable me to find them.   Or rather, it makes
finding them extremely time consuming.  

To write code that handles errors as you say is absurdly verbose:

foo = a+b;
assert(foo!=undef);  // in case a or b are mixed type
bar = foo-c;  
assert(bar!=undef);  // c might be the wrong type
x=somelist[ind];  
assert(x!=undef);  // ind might be out of bounds

etc.  Every time an instruction might produce undef I need an assert to
check for the possible error.  If I don't do this (and indeed I do not) then
the undefs propagate through the code until somewhere later, a fatal error
occurs---or maybe no error occurs but the final output is missing or wrong.
So as a practical example, a user reported that something broke in the
library I work on.  I took a look and the function in question was producing
undef.  Why?  Well, because the function it called produced undef.  But why?
Because it called a function that produced undef.  Why did that happen...and
so it goes.  Eventually after inserting many echo statements I am finally
able to identify the statement that originated the undef, and hence
understand the bug.   So it took me 15 minutes to diagnose an issue that in
a language without propagating undef would have taken 15 seconds.  Yes, it's
possible to write code that checks all the parameters and ensures
compatibility of args so that undefs don't occur.  I do this, in fact.  So
in bug free code undef works as an error handling mechanism.  But in code
that might have bugs---say I forget a check, or I screw up and check a list
against the wrong length---undef is a mess because it doesn't give
information about where the error occurred.  

I'm not sure what is going on with your example below.  Is search() being
changed to produce a warning when it doesn't find anything?  That would be
stupid.  Right now it returns an empty list.  

Yes, undef is useful when you have optional parameters.  The problem with
undef is not that it exists but that operations that are invalid produce it
as output instead of producing an immediate error.   Undef as a concept is
OK for unset parameters, for example.  What's not OK is that a+b or
list[foo] can produce undef as output.  

I'm not quite sure what it has to do with undef, but why write code where
you need to change variables?  I would write the library so that this wasn't
necessary.   Passing data with global variables isn't good coding practice,
but if it must be done for some reason you could still do it in such a way
that you don't have to redefine a variable and hende don't get a warning.  



MichaelAtOz wrote

> The current undef behaviour allows you to handle errors.
> You can detect that the result is undef and take appropriate action.
> This is particularly useful when you don't have predefined data, or
> optional
> parameters.
>
> undef causing an error would prevent that, even a warning, it is already
> problematic with warnings in for() loops or recursive code flooding the
> console.
>
> -------------------------------
>
> Loaded design 'C:/Users/MeB/Documents/3D-REPRAP/Things/My
> Things/badge.scad'.
> Parsing design (AST generation)...
> WARNING: Letter_height was assigned on line 7 but was overwritten on line
> 78
> WARNING: kh was assigned on line 8 but was overwritten on line 128
> Compiling design (CSG Tree generation)...
> ECHO: "OS V=20190500"
> ECHO: "OSLIB/Write/write.scad"
> WARNING: search term not found: "B", in file badge.scad, line 93
> WARNING: search term not found: "l", in file badge.scad, line 93
> WARNING: search term not found: "a", in file badge.scad, line 93
> WARNING: search term not found: "c", in file badge.scad, line 93
> WARNING: search term not found: "k", in file badge.scad, line 93
> WARNING: search term not found: "o", in file badge.scad, line 93
> WARNING: search term not found: "s", in file badge.scad, line 93
> WARNING: search term not found: "e", in file badge.scad, line 93
> Compiling design (CSG Products generation)...
> Geometries in cache: 129
> Geometry cache size in bytes: 852176
> CGAL Polyhedrons in cache: 1
> CGAL cache size in bytes: 1650000
> Compiling design (CSG Products normalization)...
> Compiling background (1 CSG Trees)...
> Normalized CSG tree has 93 elements
> Compile and preview finished.
> Total rendering time: 0 hours, 0 minutes, 23 seconds
>
> -----------------------------
>
> The first two are valid overwrites to overcome a include<> default
> assignment.
> The using search to not find something is perfectly valid logic, just
> lucky
> in this case the text is short.
>
>
>
> -----
> Admin - email* me if you need anything,  or if I've done something
> stupid...
>
> * click on my MichaelAtOz label, there is a link to email me.
>
> Unless specifically shown otherwise above, my contribution is in the
> Public Domain; to the extent possible under law, I have waived all
> copyright and related or neighbouring rights to this work. Obviously
> inclusion of works of previous authors is not included in the above.
>
> --
> Sent from: http://forum.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?

MichaelAtOz
Administrator
adrianv wrote
> To write code that handles errors as you say is absurdly verbose:

no not to handle programmed errors, but data input errors, where parameter
input is allowed to be 'difficult' and that the library can detect than and
do something appropriate.

> I'm not quite sure what it has to do with undef, but why write code where
> you need to change variables?  I would write the library so that this
> wasn't
> necessary.   Passing data with global variables isn't good coding
> practice,
> but if it must be done for some reason you could still do it in such a way
> that you don't have to redefine a variable and hende don't get a warning.  

That is a case of someone elses library, but that situation is common, if
you have defaults in an include<> and you want to change then and need to
use top level variables, that is then only way.

Anyway, I'm pretty sure we code differently and won't agree.



-----
Admin - email* me if you need anything,  or if I've done something stupid...

* click on my MichaelAtOz label, there is a link to email me.

Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above.

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

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Admin - email* me if you need anything, or if I've done something stupid...
* click on my MichaelAtOz label, there is a link to email me.

Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work.
Obviously inclusion of works of previous authors is not included in the above.
Reply | Threaded
Open this post in threaded view
|

Re: What happened to booleans?

doug.moen
In reply to this post by MichaelAtOz
@MichaelAtOz: In my language, I only report errors in the situations where the majority of programming languages would report an error. Examples include: performing a boolean operation on a non-bool, or a numeric operation on a non-number, or dividing by zero.

Most languages have an operation that lets you test if a list contains a specified value (without getting an error if the value isn't found). For example, in Python you can write 'x in list' and it returns False if x is not an element of list. In OpenSCAD, you accomplish the same thing using `search(x,list)!=[]`. In Javascript, `list.indexOf(x)` will return the index of x in list, or -1 if not found.

The `search` function shouldn't report an error if the element isn't found, and it shouldn't print warning messages. If you don't check the result of `search` to see if it is [], and you try to use the non-existent first element of the search result, THEN you should get an error.


On Tue, Jul 28, 2020, at 4:31 AM, MichaelAtOz wrote:

> The current undef behaviour allows you to handle errors.
> You can detect that the result is undef and take appropriate action.
> This is particularly useful when you don't have predefined data, or optional
> parameters.
>
> undef causing an error would prevent that, even a warning, it is already
> problematic with warnings in for() loops or recursive code flooding the
> console.
>
> -------------------------------
>
> Loaded design 'C:/Users/MeB/Documents/3D-REPRAP/Things/My
> Things/badge.scad'.
> Parsing design (AST generation)...
> WARNING: Letter_height was assigned on line 7 but was overwritten on line 78
> WARNING: kh was assigned on line 8 but was overwritten on line 128
> Compiling design (CSG Tree generation)...
> ECHO: "OS V=20190500"
> ECHO: "OSLIB/Write/write.scad"
> WARNING: search term not found: "B", in file badge.scad, line 93
> WARNING: search term not found: "l", in file badge.scad, line 93
> WARNING: search term not found: "a", in file badge.scad, line 93
> WARNING: search term not found: "c", in file badge.scad, line 93
> WARNING: search term not found: "k", in file badge.scad, line 93
> WARNING: search term not found: "o", in file badge.scad, line 93
> WARNING: search term not found: "s", in file badge.scad, line 93
> WARNING: search term not found: "e", in file badge.scad, line 93
> Compiling design (CSG Products generation)...
> Geometries in cache: 129
> Geometry cache size in bytes: 852176
> CGAL Polyhedrons in cache: 1
> CGAL cache size in bytes: 1650000
> Compiling design (CSG Products normalization)...
> Compiling background (1 CSG Trees)...
> Normalized CSG tree has 93 elements
> Compile and preview finished.
> Total rendering time: 0 hours, 0 minutes, 23 seconds
>
> -----------------------------
>
> The first two are valid overwrites to overcome a include<> default
> assignment.
> The using search to not find something is perfectly valid logic, just lucky
> in this case the text is short.
>
>
>
> -----
> Admin - email* me if you need anything,  or if I've done something stupid...
>
> * click on my MichaelAtOz label, there is a link to email me.
>
> Unless specifically shown otherwise above, my contribution is in the
> Public Domain; to the extent possible under law, I have waived all
> copyright and related or neighbouring rights to this work. Obviously
> inclusion of works of previous authors is not included in the above.
>
> --
> Sent from: http://forum.openscad.org/
>
> _______________________________________________
> OpenSCAD mailing list
> [hidden email]
> http://lists.openscad.org/mailman/listinfo/discuss_lists.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?

JordanBrown
This is all part of an eternal debate in software design:  when there's a situation that might represent a bug, do you call it to the developer's attention or do you try to soldier on?  If you're going to fail, how "hard" do you fail?

There is definitely ease of use in "just soldier on".  Often a program can silently ignore "error" conditions and produce the intended result, without the programmer having to take explicit action to handle an unusual condition.  Often even if the result is not "correct" it is still "close enough".

On the other hand, the more distance there is between a bug and when it's detected, the harder it will be to find the bug.

Failing "soft" - returning undef, in OpenSCAD - may feel like a happy middle ground, but because the failure can easily propagate outward a large distance it's only a bit better than not failing at all.  Nobody is going to check for that kind of error on every operation that can produce one.

I'm pretty solidly in the "fail hard as early as possible" camp.  It's sometimes a pain in the neck to work through the "unnecessary" errors, but the result is more confidence that the results are correct.


_______________________________________________
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?

MostlyHarmless


On Tue, Jul 28, 2020 at 4:05 PM Jordan Brown <[hidden email]> wrote:
I'm pretty solidly in the "fail hard as early as possible" camp.  It's sometimes a pain in the neck to work through the "unnecessary" errors, but the result is more confidence that the results are correct.

Yupp, -Werror all the way. But that is just for those who really like "no warnings missed".

Jan

 

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


--
Jan Wieck
Principal Database Engineer

_______________________________________________
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?

jon_bondy
In reply to this post by JordanBrown

I agree with Jordan.

Could there be a setting to choose between "fail early" and "fail barely"?

Jon

On 7/28/2020 4:04 PM, Jordan Brown wrote:
This is all part of an eternal debate in software design:  when there's a situation that might represent a bug, do you call it to the developer's attention or do you try to soldier on?  If you're going to fail, how "hard" do you fail?

There is definitely ease of use in "just soldier on".  Often a program can silently ignore "error" conditions and produce the intended result, without the programmer having to take explicit action to handle an unusual condition.  Often even if the result is not "correct" it is still "close enough".

On the other hand, the more distance there is between a bug and when it's detected, the harder it will be to find the bug.

Failing "soft" - returning undef, in OpenSCAD - may feel like a happy middle ground, but because the failure can easily propagate outward a large distance it's only a bit better than not failing at all.  Nobody is going to check for that kind of error on every operation that can produce one.

I'm pretty solidly in the "fail hard as early as possible" camp.  It's sometimes a pain in the neck to work through the "unnecessary" errors, but the result is more confidence that the results are correct.


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.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?

thehans
Hello everyone,

I felt I should give an update on the status of this hot topic.
I haven't had time to respond directly to all the posts here, but I want to stress that I am taking all your concerns quite seriously and am currently working to "right the wrongs" that I made in the previous change.

In my last response to this thread I was arguing that we *shouldn't* return more undefs from comparing different types, but my stance has changed on that.

I do believe it makes sense for the language to declare certain types of operations as "undefined", by returning undef (as it already does in many cases, and now for the issue of comparisons between number and bools, or basically any other mixed types).
The only problem with that, as others have already pointed out, is that OpenSCAD is doing this silently, making it hard to trace down the source of such programming errors.  So I think this would be ok as long as we can generate a warning from the source of the problem (whichever operation returns undef), before these values travel further throughout the script.
Treating this as a full Type Error which halts execution is not really an option as I don't want to break compatibility of older scripts in a major way, but there is already an option for users who would prefer this stricter behavior in Preferences -> Advanced -> "Stop on the first Warning".  (that's basically our "-Werror")

There is actually some difficulty involved in reporting useful errors/warnings from deep in the code which handles this operator logic (src/value.cc), because AST information (source file and line number) is not passed down into these low level operators.
But I think I have a solution to this which will make it possible to do this for comparison operators.  I am still working on implementing and testing it but as a quick summary:  
 - undef is currently an "empty type" , which can be used as a yes/no flag based on its type, but contains no other data.
 - I would change this type to hold a message string for *why* it was set to undef.  This way higher level code with access to the AST info can print a nice warning with line numbers in addition to whatever message the low level operator provides.

Also with such a change, it should be much easier to implement a wider variety of "Undefined Operation" types of warnings throughout the program, just about anywhere that undef is returned.

Lastly, since some users may not want to look at a bunch of new warnings on scripts that are otherwise functioning fine for them, I'm considering making these additional "Undefined Operation" warnings as a separate user-configurable option to enable/disable.


As a first step I decided to try returning undef from comparison operators on mixed types (no new warnings yet) and see how much of our existing test-suite would break.  The code change actually wasn't too involved, and was done in an hour or so.
Surprisingly only two test results required updating:
1) 'operator-tests.scad' (this checks all kinds of combinations of mixed type comparisons, and was expected to change significantly)
2) 'expression-precedence-tests.scad'   Where the expected result for this one line of nonsense code changed:  "echo(assoc_left_ltgt   = 3 < 4 > 5);"   
    Previously this evaluated to false, and with changes it is now more appropriately undef.

This seems to bode well in terms of maintaining backwards compatibility, mostly since undef will continue to evaluate to false in a boolean context.

The current Pull Request is here, if anyone wants to look it over:  https://github.com/openscad/openscad/pull/3383  Again, its still work in progress and I will update as soon as I have some added warnings working, but I welcome any feedback.
You can also try downloading one of the artifacts from the build servers to see if this sort of change would impact any of your code, such as this AppImage from CircleCI here:

I am hopeful that this issue can be resolved in a way that is acceptable to everyone, and even result in OpenSCAD becoming much stronger for it.


On Tue, Jul 28, 2020 at 3:38 PM jon <[hidden email]> wrote:

I agree with Jordan.

Could there be a setting to choose between "fail early" and "fail barely"?

Jon

On 7/28/2020 4:04 PM, Jordan Brown wrote:
This is all part of an eternal debate in software design:  when there's a situation that might represent a bug, do you call it to the developer's attention or do you try to soldier on?  If you're going to fail, how "hard" do you fail?

There is definitely ease of use in "just soldier on".  Often a program can silently ignore "error" conditions and produce the intended result, without the programmer having to take explicit action to handle an unusual condition.  Often even if the result is not "correct" it is still "close enough".

On the other hand, the more distance there is between a bug and when it's detected, the harder it will be to find the bug.

Failing "soft" - returning undef, in OpenSCAD - may feel like a happy middle ground, but because the failure can easily propagate outward a large distance it's only a bit better than not failing at all.  Nobody is going to check for that kind of error on every operation that can produce one.

I'm pretty solidly in the "fail hard as early as possible" camp.  It's sometimes a pain in the neck to work through the "unnecessary" errors, but the result is more confidence that the results are correct.


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.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?

JordanBrown
On 7/28/2020 5:02 PM, Hans L wrote:
 - I would change this type to hold a message string for *why* it was set to undef.  This way higher level code with access to the AST info can print a nice warning with line numbers in addition to whatever message the low level operator provides.

That's a very clever idea.


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

Re: What happened to booleans?

rew
In reply to this post by JordanBrown
On Tue, Jul 28, 2020 at 08:04:54PM +0000, Jordan Brown wrote:
's detected, the harder it will be to find the bug.
>
> Failing "soft" - returning undef, in OpenSCAD - may feel like a happy

Some "failures" are not failures, and need to be handled by higher
layers. The classical example is of a program going to write a file.
To prevent accidentally overwriting the file, the program will attempt
to open the file, get an error: "Can't open file", and then proceed to
write the file.

Sure you can find other ways to do this specific thing, but this is an
example where what the "open" function thought was an error, was
precisely the opposite to the program making the call.

Moving to the context of openscad: Suppose I have a module to make a
screw that takes the "head" as an argument. You could make such a
module to take a number to define what head to use out of a list of
possible heads, but lets say I've structured this differently and I
want to pass the object. (Not sure how to do that in openscad, but
lets assume I can.... Oh! I can do it with a "children" construct!)

Now what if instead of a screw I want to make a threaded rod? No head!
In this case, the module might try to access the empty list of "heads
to put on", but that's not an error. If you report the error, HARD, as
in throw an error and abort, then I can't even create that threaded
rod.

So... when talking abstractly: "You should throw errors as close as
possible to the line causing the problem." I'm all for it.... But
when you think about it, it is not as clear cut as you might think.


        Roger.

--
** [hidden email] ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.

_______________________________________________
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?

nophead
Yes making warmings optional doesn't really solve the backward compatibility option. A library maintainer would want to turn it on to make the library easy to use but would then have to fix all the intended uses of functions returning undef by adding extra code.

Perhaps it should only be an error to use undef in operations that need a concrete value, i.e. nearly everywhere, except in a boolean context, where it is simply false. If the undef value carries information of what generated it that could be part of the warning when it was used.

So something like this.
list = [];
x = list[0];  // x = undef(list index out of bounds)
if(x)
    sphere(x); // Not executed
else
   cube(x); // Error cube size parameter is undefined (list index out of bounds at line 2)



On Wed, 29 Jul 2020 at 08:11, Rogier Wolff <[hidden email]> wrote:
On Tue, Jul 28, 2020 at 08:04:54PM +0000, Jordan Brown wrote:
's detected, the harder it will be to find the bug.
>
> Failing "soft" - returning undef, in OpenSCAD - may feel like a happy

Some "failures" are not failures, and need to be handled by higher
layers. The classical example is of a program going to write a file.
To prevent accidentally overwriting the file, the program will attempt
to open the file, get an error: "Can't open file", and then proceed to
write the file.

Sure you can find other ways to do this specific thing, but this is an
example where what the "open" function thought was an error, was
precisely the opposite to the program making the call.

Moving to the context of openscad: Suppose I have a module to make a
screw that takes the "head" as an argument. You could make such a
module to take a number to define what head to use out of a list of
possible heads, but lets say I've structured this differently and I
want to pass the object. (Not sure how to do that in openscad, but
lets assume I can.... Oh! I can do it with a "children" construct!)

Now what if instead of a screw I want to make a threaded rod? No head!
In this case, the module might try to access the empty list of "heads
to put on", but that's not an error. If you report the error, HARD, as
in throw an error and abort, then I can't even create that threaded
rod.

So... when talking abstractly: "You should throw errors as close as
possible to the line causing the problem." I'm all for it.... But
when you think about it, it is not as clear cut as you might think.


        Roger.

--
** [hidden email] ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.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?

nophead
Or better this:
list = [];
x = list[0];  // x = undef(list index out of bounds at line 2)
if(x)
    sphere(x); // Not executed
else
   cube(x); // Error cube size parameter is undef(list index out of bounds at line 2) at line 6

On Wed, 29 Jul 2020 at 09:00, nop head <[hidden email]> wrote:
Yes making warmings optional doesn't really solve the backward compatibility option. A library maintainer would want to turn it on to make the library easy to use but would then have to fix all the intended uses of functions returning undef by adding extra code.

Perhaps it should only be an error to use undef in operations that need a concrete value, i.e. nearly everywhere, except in a boolean context, where it is simply false. If the undef value carries information of what generated it that could be part of the warning when it was used.

So something like this.
list = [];
x = list[0];  // x = undef(list index out of bounds)
if(x)
    sphere(x); // Not executed
else
   cube(x); // Error cube size parameter is undefined (list index out of bounds at line 2)



On Wed, 29 Jul 2020 at 08:11, Rogier Wolff <[hidden email]> wrote:
On Tue, Jul 28, 2020 at 08:04:54PM +0000, Jordan Brown wrote:
's detected, the harder it will be to find the bug.
>
> Failing "soft" - returning undef, in OpenSCAD - may feel like a happy

Some "failures" are not failures, and need to be handled by higher
layers. The classical example is of a program going to write a file.
To prevent accidentally overwriting the file, the program will attempt
to open the file, get an error: "Can't open file", and then proceed to
write the file.

Sure you can find other ways to do this specific thing, but this is an
example where what the "open" function thought was an error, was
precisely the opposite to the program making the call.

Moving to the context of openscad: Suppose I have a module to make a
screw that takes the "head" as an argument. You could make such a
module to take a number to define what head to use out of a list of
possible heads, but lets say I've structured this differently and I
want to pass the object. (Not sure how to do that in openscad, but
lets assume I can.... Oh! I can do it with a "children" construct!)

Now what if instead of a screw I want to make a threaded rod? No head!
In this case, the module might try to access the empty list of "heads
to put on", but that's not an error. If you report the error, HARD, as
in throw an error and abort, then I can't even create that threaded
rod.

So... when talking abstractly: "You should throw errors as close as
possible to the line causing the problem." I'm all for it.... But
when you think about it, it is not as clear cut as you might think.


        Roger.

--
** [hidden email] ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.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?

adrianv
In reply to this post by rew
rew wrote

> Some "failures" are not failures, and need to be handled by higher
> layers. The classical example is of a program going to write a file.
> To prevent accidentally overwriting the file, the program will attempt
> to open the file, get an error: "Can't open file", and then proceed to
> write the file.
>
> Sure you can find other ways to do this specific thing, but this is an
> example where what the "open" function thought was an error, was
> precisely the opposite to the program making the call.
>
> ....
>
> Now what if instead of a screw I want to make a threaded rod? No head!
> In this case, the module might try to access the empty list of "heads
> to put on", but that's not an error. If you report the error, HARD, as
> in throw an error and abort, then I can't even create that threaded
> rod.
>
> ...
>
> So... when talking abstractly: "You should throw errors as close as
> possible to the line causing the problem." I'm all for it.... But
> when you think about it, it is not as clear cut as you might think.

I don't think you can find other ways to test for file existence that aren't
equivalent to trying to open the file.  You can divide errors into two
kinds: preventable and not preventable.  You have no way of knowing that the
file open operation will fail except that you try it.  In OpenSCAD you don't
know that two lines are parallel until the line intersection routine runs,
so it wouldn't make sense to write a line intersection routine that issued a
fatal error on parallel lines, because the line intersection function also
needs to serve as the test for parallel lines.  

But if you calculate list[ind] you can guard against errors by not passing
it an invalid index, which is a simple matter since the valid indices are
integers with ind>=0 and ind<len(list).  If you calculate
 
a+b

in some context you can and should validate that a and b are legitimate
values before doing the calculation, which will guarantee validity of a+b.
It's an unlikely context where the validity of a+b is sufficient alone.
Some further testing is necessary to assure that the computation makes sense
in the larger context, which will ensure that a and b are compatible for
addition.  

For the example of threaded rod and lists of heads, you check the length of
the list before indexing into it.  Your example is a little weird since
screws don't have multiple heads, but if someone passes you a list to
operate on your code is going to look like:

for(entry=list){...} or for(i=[0:1:len(list)-1]){...}

and if the list had no entries, nothing would happen.   If you're passing
geometry you check $children before invoking a given child.  

I think it's pretty clear cut.  If the error is preventable then it is
reasonable to throw the error as soon as it occurs.  If the programmer
doesn't want an error then a test can be used to prevent the error.  Only in
the case where the error is not preventable does it make sense to do
something different.  Indexing out of bounds is preventable.  Are there any
OpenSCAD operations that generate undef where performing the operation is
the only way to validate it?  If there are they probably should return undef
rather than producing an immediate error.  But then if you try to do
operations on that undef you should get an immediate error.  




--
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?

JordanBrown
In reply to this post by rew
[ Please forgive my tendency to write a lot about this.  It's actually a primary interest in my professional life - how to write programs to make it difficult to have bugs, how to detect the bugs you can't prevent, and how to design languages, libraries, and other infrastructure so as to prevent and detect bugs. A related topic is "how to report errors so that the error reports are useful". ]

On 7/29/2020 12:10 AM, Rogier Wolff wrote:
Some "failures" are not failures,  [...]

So... when talking abstractly: "You should throw errors as close as possible to the line causing the problem." I'm all for it.... But when you think about it, it is not as clear cut as you might think.


Yes.  Distinguishing a likely bug from an "expected" error is important.

Nop head's "when you need a concrete answer" test is certainly a good start.  But I don't think it's quite enough.  The next question is "what is a likely bug, and what is merely missing data?".

A missing parameter (in OpenSCAD, where missing parameters are expected) is clearly not an error.  (But maybe OpenSCAD should have a syntax that says "this parameter is required".)

An attempt to divide by zero is clearly an error.  In the unlikely event that you really want something infinity-like as the result, require the programmer to explicitly check first.  (atan2() comes to mind.)

I think it's clear that if a function requires a particular parameter, then not supplying it is an error.  (But not everybody agrees.  In C, I often see people checking required parameters for NULL and returning an error if they're NULL.  No!  The parameter is required; if the caller supplied a NULL then the caller unquestionably has a bug!)

But an array index that's out of bounds?  Hard to say.  You might say it's a bug, or you might say that returning undef allows the program to probe for the dimensions of the array.  I would come down on the side of calling it an error.  If you *want* to probe for the dimensions of the array, you can use len() and then the intent is obvious.  That's a key thing:  having the program convey the programmer's intent.  If you have out-of-bounds references simply return undef, neither the interpreter nor a reviewer can tell what the intent is, and so you can't detect the bug.  If, on the other hand, you consider it an error, then you have two distinct idioms:  if your intent is to retrieve a value (and you don't expect your index to be out of bounds) then you do a simple reference; if your intent is to check for the presence of the value then you use len().  Yes, if "undef" was a reasonable default value you have to go a bit out of your way and say i < len(x) ? x[i] : undef, but that doesn't seem like an onerous price to pay for protecting all of the *other* cases.

Mixed-type expressions are particularly tricky.  There are reasonable definitions for many combinations.  I'd draw the line at the point where you have to "stretch" to say that the definition is reasonable.  String concatenation through '+' is reasonable.  String replication through multiplication seems reasonable.  Saying that boolean*string is equivalent to (boolean ? string : "") seems past the limit.  Automatic to-string when you mix a string and something else with "+"... I'm not sure.  It's reasonably obvious and awfully convenient, but is implicated in any number of cases of "null" appearing in user interfaces.

Hans's "undef with a reason" does help a lot.  I'm not sure it's enough.  Because undef is considered false for "if" purposes (a definition that seems unlikely to change) an undef that came from a bug can lead to silently going down an execution path that doesn't happen to ever use the value in a "concrete" way.


_______________________________________________
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?

nophead
The issue is that OpenSCAD has been used for many years and has always returned undef for an out of bounds index so I use it as a shortcut. Instead of if(len(type) > 3 && type[3]) is just if(type[3]), which is a lot less ugly. It saves adding empty values to the end of my object descriptors and makes the lack of an entry the same as an empty entry, which makes semantic sense to me. And len should go back to silently returning undef when applied to a scalar. Otherwise it becomes if(is_list(type) && len(type) > 3 && type[3]), which is even more ugly. In practice the list element is wrapped in an accessor function, so the intent becomes obvious. E.g.

        conn = camera_connector_size(type);
        if(conn) {
                 use conn to draw the connector
        }

I doubt there are many cases where people do if(list[n]) where it is a mistake, using list[n] to compute something or compare it to anything other than undef is definitely an error if the list isn't that long and my proposal would catch all other errors due to bad indexing.

If an undef value goes down an execution path that doesn't use it then it isn't a bug as far as I am concerned. undef exists as a value, can be assigned to variables and passed as parameters and silently tested as false with if, so I don't think that should change. But if it always stores how it became undef then debugging is easy because if you ever use it in an expression you will get a warning showing where it became undef and where it was finally used. Exactly what you need to debug.

Whether operators get overloaded to work on strings in the future doesn't matter. At the moment they don't so you get undef.


On Wed, 29 Jul 2020 at 19:09, Jordan Brown <[hidden email]> wrote:
[ Please forgive my tendency to write a lot about this.  It's actually a primary interest in my professional life - how to write programs to make it difficult to have bugs, how to detect the bugs you can't prevent, and how to design languages, libraries, and other infrastructure so as to prevent and detect bugs. A related topic is "how to report errors so that the error reports are useful". ]

On 7/29/2020 12:10 AM, Rogier Wolff wrote:
Some "failures" are not failures,  [...]

So... when talking abstractly: "You should throw errors as close as possible to the line causing the problem." I'm all for it.... But when you think about it, it is not as clear cut as you might think.


Yes.  Distinguishing a likely bug from an "expected" error is important.

Nop head's "when you need a concrete answer" test is certainly a good start.  But I don't think it's quite enough.  The next question is "what is a likely bug, and what is merely missing data?".

A missing parameter (in OpenSCAD, where missing parameters are expected) is clearly not an error.  (But maybe OpenSCAD should have a syntax that says "this parameter is required".)

An attempt to divide by zero is clearly an error.  In the unlikely event that you really want something infinity-like as the result, require the programmer to explicitly check first.  (atan2() comes to mind.)

I think it's clear that if a function requires a particular parameter, then not supplying it is an error.  (But not everybody agrees.  In C, I often see people checking required parameters for NULL and returning an error if they're NULL.  No!  The parameter is required; if the caller supplied a NULL then the caller unquestionably has a bug!)

But an array index that's out of bounds?  Hard to say.  You might say it's a bug, or you might say that returning undef allows the program to probe for the dimensions of the array.  I would come down on the side of calling it an error.  If you *want* to probe for the dimensions of the array, you can use len() and then the intent is obvious.  That's a key thing:  having the program convey the programmer's intent.  If you have out-of-bounds references simply return undef, neither the interpreter nor a reviewer can tell what the intent is, and so you can't detect the bug.  If, on the other hand, you consider it an error, then you have two distinct idioms:  if your intent is to retrieve a value (and you don't expect your index to be out of bounds) then you do a simple reference; if your intent is to check for the presence of the value then you use len().  Yes, if "undef" was a reasonable default value you have to go a bit out of your way and say i < len(x) ? x[i] : undef, but that doesn't seem like an onerous price to pay for protecting all of the *other* cases.

Mixed-type expressions are particularly tricky.  There are reasonable definitions for many combinations.  I'd draw the line at the point where you have to "stretch" to say that the definition is reasonable.  String concatenation through '+' is reasonable.  String replication through multiplication seems reasonable.  Saying that boolean*string is equivalent to (boolean ? string : "") seems past the limit.  Automatic to-string when you mix a string and something else with "+"... I'm not sure.  It's reasonably obvious and awfully convenient, but is implicated in any number of cases of "null" appearing in user interfaces.

Hans's "undef with a reason" does help a lot.  I'm not sure it's enough.  Because undef is considered false for "if" purposes (a definition that seems unlikely to change) an undef that came from a bug can lead to silently going down an execution path that doesn't happen to ever use the value in a "concrete" way.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.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?

adrianv
There's no reason this is true.  What if I have a parameter, x, and I want to
based a decision on the value of x, but in some complex way, so I write

f(x) ? g(x) : h(x)

but unfortunately, the function f has a bug and sometimes produces undef
when it should produce true.  My code now silently executes h(x) when it
should instead run g(x) and there's no sign of the mistake.  Maybe this
later leads to a failure of some kind?  But it's not direct.  The idea that
bugs can only occur if the expression is used outside a boolean context is
incorrect.  

A simpler and less complex case would be a decision parameter mistakenly
ends up somehow as undef and hence gets interpreted as false.  The program
doesn't produce bad output, but it produces the wrong output, which is a
bug. This might happen if the programmer mistyped a variable name, for
example.  

if (add_dooodad) { make_doodad(..)}

This is always false since add_dooodad was spelled wrong so it is undef, and
so the doodad is never created, and the programmer is absolutely baffled
because the code looks correct, and add_doodad is definitely set to true.  


nophead wrote

> If an undef value goes down an execution path that doesn't use it then it
> isn't a bug as far as I am concerned. undef exists as a value, can be
> assigned to variables and passed as parameters and silently tested as
> false
> with if, so I don't think that should change. But if it always stores how
> it became undef then debugging is easy because if you ever use it in an
> expression you will get a warning showing where it became undef and where
> it was finally used. Exactly what you need to debug.
>
> Whether operators get overloaded to work on strings in the future doesn't
> matter. At the moment they don't so you get undef.
>
>
> On Wed, 29 Jul 2020 at 19:09, Jordan Brown &lt;

> openscad@.maileater

> &gt;
> wrote:
>
>> [ Please forgive my tendency to write a lot about this.  It's actually a
>> primary interest in my professional life - how to write programs to make
>> it
>> difficult to have bugs, how to detect the bugs you can't prevent, and how
>> to design languages, libraries, and other infrastructure so as to prevent
>> and detect bugs. A related topic is "how to report errors so that the
>> error
>> reports are useful". ]
>>
>> On 7/29/2020 12:10 AM, Rogier Wolff wrote:
>>
>> Some "failures" are not failures,  [...]
>>
>> So... when talking abstractly: "You should throw errors as close as
>> possible to the line causing the problem." I'm all for it.... But when
>> you
>> think about it, it is not as clear cut as you might think.
>>
>>
>> Yes.  Distinguishing a likely bug from an "expected" error is important.
>>
>> Nop head's "when you need a concrete answer" test is certainly a good
>> start.  But I don't think it's quite enough.  The next question is "what
>> is
>> a likely bug, and what is merely missing data?".
>>
>> A missing parameter (in OpenSCAD, where missing parameters are expected)
>> is clearly not an error.  (But maybe OpenSCAD should have a syntax that
>> says "this parameter is required".)
>>
>> An attempt to divide by zero is clearly an error.  In the unlikely event
>> that you really want something infinity-like as the result, require the
>> programmer to explicitly check first.  (atan2() comes to mind.)
>>
>> I think it's clear that if a function requires a particular parameter,
>> then not supplying it is an error.  (But not everybody agrees.  In C, I
>> often see people checking required parameters for NULL and returning an
>> error if they're NULL.  No!  The parameter is required; if the caller
>> supplied a NULL then the caller unquestionably has a bug!)
>>
>> But an array index that's out of bounds?  Hard to say.  You might say
>> it's
>> a bug, or you might say that returning undef allows the program to probe
>> for the dimensions of the array.  I would come down on the side of
>> calling
>> it an error.  If you *want* to probe for the dimensions of the array, you
>> can use len() and then the intent is obvious.  That's a key thing:
>> having the program convey the programmer's intent.  If you have
>> out-of-bounds references simply return undef, neither the interpreter nor
>> a
>> reviewer can tell what the intent is, and so you can't detect the bug.
>> If,
>> on the other hand, you consider it an error, then you have two distinct
>> idioms:  if your intent is to retrieve a value (and you don't expect your
>> index to be out of bounds) then you do a simple reference; if your intent
>> is to check for the presence of the value then you use len().  Yes, if
>> "undef" was a reasonable default value you have to go a bit out of your
>> way
>> and say i < len(x) ? x[i] : undef, but that doesn't seem like an onerous
>> price to pay for protecting all of the *other* cases.
>>
>> Mixed-type expressions are particularly tricky.  There are reasonable
>> definitions for many combinations.  I'd draw the line at the point where
>> you have to "stretch" to say that the definition is reasonable.  String
>> concatenation through '+' is reasonable.  String replication through
>> multiplication seems reasonable.  Saying that boolean*string is
>> equivalent
>> to (boolean ? string : "") seems past the limit.  Automatic to-string
>> when you mix a string and something else with "+"... I'm not sure.  It's
>> reasonably obvious and awfully convenient, but is implicated in any
>> number
>> of cases of "null" appearing in user interfaces.
>>
>> Hans's "undef with a reason" does help a lot.  I'm not sure it's enough.
>> Because undef is considered false for "if" purposes (a definition that
>> seems unlikely to change) an undef that came from a bug can lead to
>> silently going down an execution path that doesn't happen to ever use the
>> value in a "concrete" way.
>>
>> _______________________________________________
>> 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?

nophead
Well then it is a trade off between people that like to write succinct code versus those that write bugs.

The point is OpenSCAD has this feature, so in order to maintain backwards compatibility it should keep it. Does it make sense I have to add more and more code to make OpenSCAD do what it used to do without complaining?

if (add_dooodad) { make_doodad(..)}  already creates a warning because you have used a variable that does not exist, different from using an expression that yields undef.
 

On Wed, 29 Jul 2020 at 21:55, adrianv <[hidden email]> wrote:
There's no reason this is true.  What if I have a parameter, x, and I want to
based a decision on the value of x, but in some complex way, so I write

f(x) ? g(x) : h(x)

but unfortunately, the function f has a bug and sometimes produces undef
when it should produce true.  My code now silently executes h(x) when it
should instead run g(x) and there's no sign of the mistake.  Maybe this
later leads to a failure of some kind?  But it's not direct.  The idea that
bugs can only occur if the expression is used outside a boolean context is
incorrect. 

A simpler and less complex case would be a decision parameter mistakenly
ends up somehow as undef and hence gets interpreted as false.  The program
doesn't produce bad output, but it produces the wrong output, which is a
bug. This might happen if the programmer mistyped a variable name, for
example. 

if (add_dooodad) { make_doodad(..)}

This is always false since add_dooodad was spelled wrong so it is undef, and
so the doodad is never created, and the programmer is absolutely baffled
because the code looks correct, and add_doodad is definitely set to true. 


nophead wrote
> If an undef value goes down an execution path that doesn't use it then it
> isn't a bug as far as I am concerned. undef exists as a value, can be
> assigned to variables and passed as parameters and silently tested as
> false
> with if, so I don't think that should change. But if it always stores how
> it became undef then debugging is easy because if you ever use it in an
> expression you will get a warning showing where it became undef and where
> it was finally used. Exactly what you need to debug.
>
> Whether operators get overloaded to work on strings in the future doesn't
> matter. At the moment they don't so you get undef.
>
>
> On Wed, 29 Jul 2020 at 19:09, Jordan Brown &lt;

> openscad@.maileater

> &gt;
> wrote:
>
>> [ Please forgive my tendency to write a lot about this.  It's actually a
>> primary interest in my professional life - how to write programs to make
>> it
>> difficult to have bugs, how to detect the bugs you can't prevent, and how
>> to design languages, libraries, and other infrastructure so as to prevent
>> and detect bugs. A related topic is "how to report errors so that the
>> error
>> reports are useful". ]
>>
>> On 7/29/2020 12:10 AM, Rogier Wolff wrote:
>>
>> Some "failures" are not failures,  [...]
>>
>> So... when talking abstractly: "You should throw errors as close as
>> possible to the line causing the problem." I'm all for it.... But when
>> you
>> think about it, it is not as clear cut as you might think.
>>
>>
>> Yes.  Distinguishing a likely bug from an "expected" error is important.
>>
>> Nop head's "when you need a concrete answer" test is certainly a good
>> start.  But I don't think it's quite enough.  The next question is "what
>> is
>> a likely bug, and what is merely missing data?".
>>
>> A missing parameter (in OpenSCAD, where missing parameters are expected)
>> is clearly not an error.  (But maybe OpenSCAD should have a syntax that
>> says "this parameter is required".)
>>
>> An attempt to divide by zero is clearly an error.  In the unlikely event
>> that you really want something infinity-like as the result, require the
>> programmer to explicitly check first.  (atan2() comes to mind.)
>>
>> I think it's clear that if a function requires a particular parameter,
>> then not supplying it is an error.  (But not everybody agrees.  In C, I
>> often see people checking required parameters for NULL and returning an
>> error if they're NULL.  No!  The parameter is required; if the caller
>> supplied a NULL then the caller unquestionably has a bug!)
>>
>> But an array index that's out of bounds?  Hard to say.  You might say
>> it's
>> a bug, or you might say that returning undef allows the program to probe
>> for the dimensions of the array.  I would come down on the side of
>> calling
>> it an error.  If you *want* to probe for the dimensions of the array, you
>> can use len() and then the intent is obvious.  That's a key thing:
>> having the program convey the programmer's intent.  If you have
>> out-of-bounds references simply return undef, neither the interpreter nor
>> a
>> reviewer can tell what the intent is, and so you can't detect the bug.
>> If,
>> on the other hand, you consider it an error, then you have two distinct
>> idioms:  if your intent is to retrieve a value (and you don't expect your
>> index to be out of bounds) then you do a simple reference; if your intent
>> is to check for the presence of the value then you use len().  Yes, if
>> "undef" was a reasonable default value you have to go a bit out of your
>> way
>> and say i < len(x) ? x[i] : undef, but that doesn't seem like an onerous
>> price to pay for protecting all of the *other* cases.
>>
>> Mixed-type expressions are particularly tricky.  There are reasonable
>> definitions for many combinations.  I'd draw the line at the point where
>> you have to "stretch" to say that the definition is reasonable.  String
>> concatenation through '+' is reasonable.  String replication through
>> multiplication seems reasonable.  Saying that boolean*string is
>> equivalent
>> to (boolean ? string : "") seems past the limit.  Automatic to-string
>> when you mix a string and something else with "+"... I'm not sure.  It's
>> reasonably obvious and awfully convenient, but is implicated in any
>> number
>> of cases of "null" appearing in user interfaces.
>>
>> Hans's "undef with a reason" does help a lot.  I'm not sure it's enough.
>> Because undef is considered false for "if" purposes (a definition that
>> seems unlikely to change) an undef that came from a bug can lead to
>> silently going down an execution path that doesn't happen to ever use the
>> value in a "concrete" way.
>>
>> _______________________________________________
>> 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

_______________________________________________
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?

Ronaldo
Well then it is a trade off between people that like to write succinct code versus those that write bugs. 
 
Well, I don't like bugs. I prefer to be cautious than lazy. Anyway, isn't that succinct enough?

function in_bounds(var,i) = is_list(var) && i>=0 && i<len(var);
...
if(in_bounds(arr)) ...

_______________________________________________
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?

nophead
No it's horrible. Instead of

function camera_connector_size(type)= type[6];

It would be 

function camera_connector_size(type)= in_bounds(type, 6) ? type[6] : false;

Longer, slower, less readable.



On Wed, 29 Jul 2020 at 22:56, Ronaldo Persiano <[hidden email]> wrote:
Well then it is a trade off between people that like to write succinct code versus those that write bugs. 
 
Well, I don't like bugs. I prefer to be cautious than lazy. Anyway, isn't that succinct enough?

function in_bounds(var,i) = is_list(var) && i>=0 && i<len(var);
...
if(in_bounds(arr)) ...
_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.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?

adrianv
Yeah, I'm with Ronaldo that I'd rather have a little bit more code than bugs.  

function ind(list,i) = is_list(list) && i>=0 && i<len(i) &amp;&amp; list[i]
? list[i] : 0;

function camera_connector_sizes(type) = ind(list,6);

This seems equally readable to me as list[6] and significantly less obscure.
Succinct is not always more readable or better when it means more cryptic or
obscure, and the form you prefer is definitely more obscure---someone
reading the code would have a harder time grasping the full implication, I
think.  

The speed complaint is bogus.  I already tested the speed consequences of
this and it saves less than a microsecond.  Are you doing this a hundred
million times?  

&lt;quote author=&quot;nophead&quot;>
No it's horrible. Instead of

function camera_connector_size(type)= type[6];

It would be

function camera_connector_size(type)= in_bounds(type, 6) ? type[6] : false;

Longer, slower, less readable.



On Wed, 29 Jul 2020 at 22:56, Ronaldo Persiano &lt;rcmpersiano@&gt;
wrote:

> Well then it is a trade off between people that like to write
>> succinct code versus those that write bugs.
>
>
> Well, I don't like bugs. I prefer to be cautious than lazy. Anyway, isn't
> that succinct enough?
>
> function in_bounds(var,i) = is_list(var) && i>=0 && i&lt;len(var);
&gt; ...
> if(in_bounds(arr)) ...
> _______________________________________________
> 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?

nophead
>Are you doing this a hundred million times?     

Due to the bug in OpenSCAD where it evaluates every expression hundreds of thousands of times the time taken to parse my code and instantiate modules dominates after the first time where all the geometry is cached. Since ind() would be a global function, I think each time it is called all my global constants would get evaluated again.

Each operation might only take microseconds because PCs are basically very fast but when there are explosions of complexity the time taken gets exponential, making large projects impractical. I.e. there is a finite limit to how big a project I can make and I am constantly looking for speed optimisations. My current project has 1355 vitamins in it and probably only half complete. Each one is described by a list and every property in the list is read by an accessor function to isolate the list format. Of course record structure with named fields would save a lot of this boilerplate code.





On Wed, 29 Jul 2020 at 23:37, adrianv <[hidden email]> wrote:
Yeah, I'm with Ronaldo that I'd rather have a little bit more code than bugs. 

function ind(list,i) = is_list(list) && i>=0 && i<len(i) &amp;&amp; list[i]
? list[i] : 0;

function camera_connector_sizes(type) = ind(list,6);

This seems equally readable to me as list[6] and significantly less obscure.
Succinct is not always more readable or better when it means more cryptic or
obscure, and the form you prefer is definitely more obscure---someone
reading the code would have a harder time grasping the full implication, I
think. 

The speed complaint is bogus.  I already tested the speed consequences of
this and it saves less than a microsecond.  Are you doing this a hundred
million times?   

&lt;quote author=&quot;nophead&quot;>
No it's horrible. Instead of

function camera_connector_size(type)= type[6];

It would be

function camera_connector_size(type)= in_bounds(type, 6) ? type[6] : false;

Longer, slower, less readable.



On Wed, 29 Jul 2020 at 22:56, Ronaldo Persiano &lt;rcmpersiano@&gt;
wrote:

> Well then it is a trade off between people that like to write
>> succinct code versus those that write bugs.
>
>
> Well, I don't like bugs. I prefer to be cautious than lazy. Anyway, isn't
> that succinct enough?
>
> function in_bounds(var,i) = is_list(var) && i>=0 && i&lt;len(var);
&gt; ...
> if(in_bounds(arr)) ...
> _______________________________________________
> 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

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