Skip to content

Conditional continuation operator for options #9161

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

Closed
wants to merge 6 commits into from

Conversation

PMunch
Copy link
Contributor

@PMunch PMunch commented Oct 3, 2018

This adds a Rust-like ?. operator to Nim which will only evaluate further if the value of the preceding option is a some. In that case it will unwrap the value and pass it on to the right hand side. The entire thing returns an option of the final value, or none if the left hand side is a none, or nothing in case the right hand side doesn't return anything.

Depends on PR #9160

@zah
Copy link
Member

zah commented Oct 3, 2018

This is usually called "existential operator". I think it's better if you use this name in the docs. Searching for "continuation operator" in Google brings results for "line continuation"

@PMunch
Copy link
Contributor Author

PMunch commented Oct 3, 2018

Aah, good idea. Wasn't really sure what to call this

injected = nnkDotExpr.newTree(
nnkDotExpr.newTree(opt, newIdentNode("unsafeGet")), firstBarren)

result = quote do:
Copy link
Member

Choose a reason for hiding this comment

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

Will cause performance problems.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That it's wrapped in a proc? Any idea how to avoid it?

Copy link
Member

Choose a reason for hiding this comment

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

this pattern (https://en.wikipedia.org/wiki/Immediately-invoked_function_expression) in Nim can use block expressions:

var i = 0
let a = block:
  if i == 0:
    i+2
  else:
    i*3
echo a

Copy link
Contributor Author

@PMunch PMunch Oct 16, 2018

Choose a reason for hiding this comment

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

The logic in the current procedure is not that simple though, this is what would be generated for something that returns a value:

(proc (): auto =
  let :tmp130615 = x
  if :tmp130615.isSome:
    return some(:tmp130615.unsafeGet.slice(3)[0]))()

As you can see it uses auto as the type and relies on Nim to create the default none value regardless of the type, so it doesn't have an else branch to the if case. I tried wrapping this up in a block statement, but without luck.

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
result = quote do:
result = quote do:
(proc (): auto {.inline.} =

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah making it inline is probably a good idea, but if I apply your suggested cange it would be a double proc wouldn't it? Not sure how this new, fancy, GitHub feature works :P

Copy link
Member

Choose a reason for hiding this comment

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

oh i see, guess I used that new feature wrong myself; maybe just apply the change manually then

Copy link
Member

Choose a reason for hiding this comment

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

## will be ``Option[T]`` where ``T`` is the returned type of ``statements``.
## If nothing is returned from ``statements`` this returns nothing.
##
## .. code-block:: nim
Copy link
Member

@timotheecour timotheecour Oct 15, 2018

Choose a reason for hiding this comment

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

runnableExamples + doAssert's instead of echo's ? (otherwise nothing guarantees it stays in sync or keeps compiling)

@Araq
Copy link
Member

Araq commented Oct 15, 2018

Existential operator. Works like regular dot-chaining,

It doesn't, a.b[c] is parsed as (a.b)[c], a?.b[c] is parsed as a.?(b[c])

@PMunch
Copy link
Contributor Author

PMunch commented Oct 16, 2018

Well it rewrites it to something that should work with the original order:
a.?b[c]
becomes:

(proc (): auto =
  let x = a # In case `a` is a procedure that returns an option
  if x.isSome: # Note that this has no else branch, relies on `auto` and the default value of `option` to resolve this
    some(x.unsafeGet.b[c])
)()

Shouldn't that keep the ordering the same?

return some(`injected`)
)()

when isMainModule:
Copy link
Member

@timotheecour timotheecour Oct 16, 2018

Choose a reason for hiding this comment

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

toptionsutil.nim? see #9328 (I'm not sure if your test will be run by CI unless something else in testament calls it) /cc @Araq

@narimiran
Copy link
Member

Now we have optionsutils package which implements all the features proposed in this PR. Closing.

@narimiran narimiran closed this Aug 13, 2019
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.

5 participants