Skip to content
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

Add support for units of measure #1454

Open
wants to merge 84 commits into
base: horizon
Choose a base branch
from

Conversation

BenMusch
Copy link
Contributor

@BenMusch BenMusch commented Jun 18, 2019

PR for the work demo'd here

This adds support for units of measure in the runtime type system, but not for the static type-checker. There is currently no way to "define" a unit. Instead, the base unit values are effectively treated as strings and checked for literal equality

Most of it is complete to my knowledge, with some notes:

  • Runtime error messages are not complete in the render-fancy-reason method. They all call render-reason right now, but I plan on changing that Fixed on 6/21
  • There are a handful of TODOs about numeric operations I think might be able to support units, but wanted feedback on those before adding it
  • I didn't update pitometer/* files, I'll do that once the work here is finalized so I don't have to re-do any work as I change any of the src/* code

@shriram
Copy link
Member

shriram commented Jun 18, 2019

Just wanted to say how very awesome this is. Thanks! (Been discussing it w/ @blerner .)

@sorawee
Copy link
Contributor

sorawee commented Jun 19, 2019

Totally agreed with Shriram. This is very cool.

Bug report:

1%<u ^ 10000000000000001> == 1%<u ^ 10000000000000000>

returns true.

return RUNTIME.getField(ast, 'u-base')
.app(pos(node.pos), name(node.kids[0]))
} else if (node.kids.length === 1 && node.kids[0].name === 'NUMBER') {
if (node.kids[0].value !== '1') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would probably be better handled as a well-formedness error later, rather than a parse-error now. Also, 1%<3> currently triggers an internal error rather than any clean error, so there's some more cleanup needed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only hold-up with making this a wf check is that we have to change u-one(l) into u-num(l, n). Not a major issue, something just feels weird about holding onto this value in the AST just for the sake of a wf check. Do you think it's worth holding onto?

@BenMusch
Copy link
Contributor Author

Thanks @shriram and thanks for the bug report @sorawee! Will push a fix for the bug tomorrow

@sorawee
Copy link
Contributor

sorawee commented Jun 23, 2019

Is there a predicate that distinguishes 1 and 1%<u>? is-number seems to accept both.

@BenMusch
Copy link
Contributor Author

@sorawee You would have to use the %<u> annotation there, you can see some examples here: https://github.com/brownplt/pyret-lang/pull/1454/files#diff-31f9ba2796b29ca0fb036e1d44797b4c

There's no function like has-unit(u) since units are not first-class values.

unit-atom: (PARENNOSPACE|PARENSPACE) unit-expr RPAREN
| NAME
| unit-atom CARET NUMBER
| NUMBER
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this now ToDone? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep!

@sorawee
Copy link
Contributor

sorawee commented Jun 23, 2019

IMO, annotation is for assertion, while predicate is for control, so they are not really equivalent. But yeah, non-first class value seems to be the problem here.

@blerner
Copy link
Member

blerner commented Jun 23, 2019

Having a predicate here would allow programs to be non-parametric in their handling of units. The only two sensible behaviors I'd like are either "this function handles exactly this unit" or "this function is parametric over units". Anything else would allow students to be inconsistent with their units (e.g. "darn it this time it had the wrong units, ok, lemme check for that and cancel them out", instead of "wait why do I have inconsistent units in the first place?"), which seems counterproductive...

@BenMusch
Copy link
Contributor Author

BenMusch commented Jul 15, 2019

Took some screenshots to showcase what the different runtime errors look like. I hard-coded conditional branches to be true/false to cover all of the statements in the rendering functions. Sorry for the large images.

Errors when stack locs and asts are available:

everything-available

When the ast is not available:

without-ast

When no source file is available:

no-src-available

When no stack loc is available:

no-stack-loc

When 'is-builtin` is true:

is-builtin

@blerner
Copy link
Member

blerner commented Jul 15, 2019

Looks good. The main grammatical complaint is the Test 1 failures, where the last sentence just begins, "unit annotated ...", rather than "The unit annotated", or better yet, "The <...> unit annotated ..." (if you have the unit available and can render it)

We need to return quickly if the arguments are identical and are not numbers, but need to avoid the identical-ness check for numbers so that we can return false in the case of within(1%<m>)(1%<s>, 1%<s>). The previous code had a logic bug where it skipped identical-ness checks on all within() calls, when it should only skip them for within() calls on numbers
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

Successfully merging this pull request may close these issues.

None yet

4 participants