Skip to content

Conditional continuation operator for options#9161

Closed
PMunch wants to merge 6 commits intonim-lang:develfrom
PMunch:optionscondcont
Closed

Conditional continuation operator for options#9161
PMunch wants to merge 6 commits intonim-lang:develfrom
PMunch:optionscondcont

Conversation

@PMunch
Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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