nim-lang / RFCs

A repository for your Nim proposals.
135 stars 26 forks source link

discardable for templates #327

Closed metagn closed 3 years ago

metagn commented 3 years ago
template foo: int {.discardable.} = 3

foo()

Don't know if it should be supported for untyped. Instead of checking the return type at the declaration site it would have to instantiate the template every time its called, get its type, then check if it is discardable at that callsite. If this is possible, then it could probably be extended to macros as well.

Could be useful for something like this:

template `:=`(a, b): untyped {.discardable.} =
  let a = b
  a

foo := 1
if bar := false:
  doAssert bar

Just to get it out, this proposal is void if it's decided that discardable in general is not worth supporting, but if it is worth supporting then this would help the feature have more of a universal availability.

Araq commented 3 years ago

The idiom is (a = b; a) and works well. Better than Python's new ugly C-isms that never made much sense.

metagn commented 3 years ago

It does work well, but I have seen people request that operator for easier migration from Python (don't know if it's because they actually used it in the code they were migrating). Implicitly discardable calls only applying to procedures would just be odd to the people that were using discardable already. That applies to templates which are just procs but as AST replacements, and also to emulators of what would be language-level syntax in another language but are trivial to implement as user code in Nim like :=.

Basically this change would only help people using discardable, it wouldn't really benefit others. While it would be kind of weird to think of discardable as a feature you "grow out of" before you learn how to really use Nim, I do think it is understandable to think it will eventually be removed, but if it's not going to be removed any time soon then this is the next obvious step to the feature IMO. I just found out that the manual actually specifically points this case out, implying someone using discardable is likely to encounter this.

Perhaps discardable needs a significant overhaul to make this work, in which case it might not be worth bothering, if so then a minor improvement would be {.discardable.} on template giving a proper error like "discardable is not supported on templates" as it currently gives "cannot attach a custom pragma".

Araq commented 3 years ago

Maybe we can make discardable more useful by attaching it to an expression and not just to a proc:


({.discardable.} 3) 

This seems easy to implement and naturally allows for usage in a template:


template foo: int = ({.discardable.} 3)

foo()

(I don't know whether I like to enhance the support for .discardable, but if we do it, we should do it right. ;-) )

metagn commented 3 years ago

I don't know how I missed it, this is actually possible in current Nim:

proc discardable[T](x: T): T {.discardable, inline.} = x

template `:=`(a, b): untyped =
  let a = b
  discardable a

foo := 1
if bar := false:
  doAssert bar

This is good enough to close the issue, it would be perfect if it's possible to completely elide the discardable proc but it's not worth the effort for such a small reward. One thing is the signature needs to be proc discardable[T](x: lent T): lent T for no copies I believe? but you can't lent ints so you would have to specialize it. I don't think the discussion of "the most optimal identity proc" is relevant to this issue so I'll just close

Araq commented 3 years ago

You should use proc discardable[T](x: sink T): T. :-)