Skip to content

Improve error handling #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
bennlich opened this issue Feb 22, 2021 · 13 comments
Open

Improve error handling #30

bennlich opened this issue Feb 22, 2021 · 13 comments

Comments

@bennlich
Copy link
Collaborator

Right now turtle.forward('dogs') or just turtle.forward(undefined) leaves turtle in a broken state, stranded at NaN, NaN. Instead, turtle.forward('dogs') should raise a ValueError.

I noticed this when editing running code in the landing page tutorial.

@bennlich bennlich changed the title turtle.forward(distance) should assert distance is a number turtle.forward(distance) should throw exception if distance is not a number Feb 22, 2021
@backspaces
Copy link
Owner

Won't this lead to a huge amount of error checking everywhere? I realize we've decided on a different audience than initially (I.e. JS programmer to novice), but I'd like to minimize the disruption.

We could use defaults for more method arguments, so something like forward(d = 1). Probably should use distance rather than d.

Math.sin('dog') returns NaN for example. It doesn't throw an error, alas, but then STEM folks may not know about try/catch.

If we do want to have special things for the novice user, I think I'd like to take the approach of creating a NL "app" which doesn't use MV split or radians or ... See the list I posted in AS channel on how to get to degrees & headings.

@bennlich
Copy link
Collaborator Author

Here's what I did that made me run into that error:

  1. Click run forever on one of the blocks that moves turtles
  2. Try changing forward(1) to forward(10). All good.
  3. Now try changing to forward(5). When you get to forward(), the turtles positions become NaN, and you can't restore them without resetting the model.

Math.sin('dog') returns NaN for example.

I think returning NaN is fine behavior. But letting the turtle's internal state become NaN is bad because then you can never get out.

Won't this lead to a huge amount of error checking everywhere?

That's a good question. It looks like this also happens with turtle.rotate(). Maybe we can survey and see how many places this would show up.

@backspaces
Copy link
Owner

Check out the slack chat:
https://redfishgroup.slack.com/archives/C033X4FF8/p1614118299077300

It could be that we solve error checking depending on how we resolve JS <> NL geometry.

Part of me thinks we should leave AS as a JS geometry with simple utils,js helper functions dealing with conversions such as radians<>degrees & euclidean<>compas geometry. If so, it would be easy for these helpers to also do error checking.

Similarly, I'm looking into a transform approach of the 40 functions that need it. They would pass all angles, relative or absolute, thru the utils.js helpers, thus also being able to check them.

But that doesn't solve the positions. But setxy & setxyz could just multiply all their args and if a NaN pops out, we throw an Error.

But I completely agree, it would be great to have deeper error checking. And you get to find most of them with your fresh eyes! Thanks!

@backspaces
Copy link
Owner

@backspaces backspaces changed the title turtle.forward(distance) should throw exception if distance is not a number Improve error handling Feb 24, 2021
@bennlich
Copy link
Collaborator Author

bennlich commented Apr 24, 2021

@backspaces I did a little user-testing of the homepage tutorial, and this came up again. I think we should figure out a solution before launching the new site.

This problem shows up specifically in a live-update situation, where a snippet of code is getting constantly re-evaluated while being edited.

My specific desire is: prevent turtle x, y from ever becoming NaN due to a call to e.g. turtle.forward() or turtle.rotate() with no args.

The more general way to say it is: prevent the model from ever entering a "bad state" due to an improper function call. A "bad state" is one that can't be recovered from without rebuilding the whole model. But for launch, I think we should just solve the specific case of the turtle NaNs.

setxy & setxyz could just multiply all their args and if a NaN pops out, we throw an Error.

Does this still seem like a reasonable way to go?

@backspaces
Copy link
Owner

Agreed, wouldn't hurt. Time for AS to grow up!

@backspaces
Copy link
Owner

Does TypeScript handle errors for you?

@backspaces
Copy link
Owner

@cody points out TS type checks at compile time so isn't that useful unless the modeler uses TS and we supply type info. Even then, it probably isn't what we want, which is inherently runtime checking.

I guess a set of type utilities may be useful, but because JS pretty much sucks at that (no Integers, too primitive in general)

@bennlich
Copy link
Collaborator Author

If you're worried about performance hits, maybe we could have only a dev build that does these checks?

@stigmergic
Copy link
Collaborator

Yes I hear the concern over adding a ton of error checking code, what a PITA. But I agree that given the audience we are targeting (novice) we want to protect them.

I think this calls for a type sanity check--as we are mostly expecting numbers as arguments we could start with just ensuring that the arguments are number like values (Number(arg) !== NaN), throwing an error for a try/catch would be the cleanest dev friendly approach. A user friendly approach might be a noop and emitting a warning to the log.

if (Number(arg) !== NaN) {
  console.warn('argument passed was not a number.  Got this instead: ', arg);
  return;
}

It does add some overhead, I'd be interested in how much.

@bennlich
Copy link
Collaborator Author

I'm monkey-patching Turtle3D in the IDE and tutorial for now:

import Turtle3D from '/agentscript/src/Turtle3D.js'

let check = (d) => {
  if (typeof d !== 'number') {
    throw new Error(`Function expected a number, got ${d}`)
  }
}

Turtle3D.prototype._forward = Turtle3D.prototype.forward
Turtle3D.prototype.forward = function(d) {
  check(d)
  this._forward(d)
}

Ditto for right, left, and rotate.

@backspaces
Copy link
Owner

This is a Good Thing!

Sorry for my getting behind. And I wasn't clear where the most important issues are for you: docs, one-pagers refactoring, etc.

I take it that error checking is the most important? It makes sense due to the IDE being interactive. And I like the check function approach.

Are you mainly concerned about Turtle2D? Maybe 3D?

I'm fine dropping my current stuff to get back into helping.

@backspaces
Copy link
Owner

OK, I committed and npm published a first pass of error checking.

  • util: add two error checking functions util/checkArg() & checkArgs()
  • Turtle3D: added their use to most/all public methods
  • I checked it with the deno unit test, test.geom.js. Found a bug, yay!

Let me know if it works. I'll look at Turtle2D to see if it needs checking too, Turtle3D subclasses it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants