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

Pragma to mark symbol-imitating templates/macros #466

Open
metagn opened this issue Jul 11, 2022 · 5 comments
Open

Pragma to mark symbol-imitating templates/macros #466

metagn opened this issue Jul 11, 2022 · 5 comments

Comments

@metagn
Copy link
Contributor

metagn commented Jul 11, 2022

Title

Symbol-imitating template pragma

Abstract

Add a pragma (no decided name yet) that marks nullary templates/macros as meant to be called in symbol format.

Motivation

Nullary templates are often used as an "aliases" to complex paths and addresses:

type
  B = object
    c: int
  A = object
    b: B
  Foo = object
    a: A

var foo: Foo
template c: untyped = foo.a.b.c
c = 3
echo foo # (a: (b: (c: 3)))

However they are still treated as "routines" and are subject to overloading. For example, you can't call them directly as aliases to other procs and other things like templates not giving redefinition errors in the same scope can also cause problems. The point being that distinguishing this use of templates and macros from regular function calls may be desirable, even as a cosmetic annotation with no functional differences.

Description

There is some old discussion on this but I don't have the links at hand. It's not really big enough of a feature for an RFC but I decided to make one just to flesh it out.

It's likely best for this pragma to not prevent normal nullary templates from being called in symbol form, nor should it require templates that use it to be called in symbol form. It would just mark the intended use. Currently it could be used for disallowing redefinitions:

template foo: int {.symbol.} = 3
template foo: int {.symbol.} = 4 # redefinition error

or allowing proc aliases:

template echo2: untyped = echo
echo2 "hello"
# (echo2)("hello") actually currently works

or maybe some different overloading behavior.

But it's fine if none of these get implemented (even the redefinition bug is circumventable by using macros), it can just serve as a guide for users on how to use certain templates/macros, similarly to {.pure.}.

Code Examples

Provided some above, honestly since the pragma being a no-op would also implement this RFC the only guaranteed examples are just the normal uses of the symbol call feature I've used 10 different names for already.

type Foo = object
  bar: int

var foo = Foo(bar: 10)
template bar: untyped {.symbol.} = foo.bar
assert bar == 10
bar = 15
assert bar == 15

Backwards Compatibility

If the pragma is a no-op, completely backwards compatible, except old versions would need a shim.

Since it's an opt-in pragma, behavior specific to it is backwards compatible, as long as the behavior of regular templates is kept the same.

However, if desired, the behavior of unmarked templates could be changed to disallow some things, example being like this (modified from nim-lang/Nim#7803):

type
  Foo = object

proc body(foo: Foo): string = "asd"

block:
  template body: var string = x

  var x = "hello"
  body.add("foobar") # overload error without pragma, works with pragma
@demotomohiro
Copy link

I think most of these using a template as an alias can be replaced by view types:
https://nim-lang.github.io/Nim/manual_experimental.html#view-types

@metagn
Copy link
Contributor Author

metagn commented Jul 20, 2022

That's not necessarily the only use of this. I usually hesitate to make posts like this because you have to mention examples and if you don't mention enough, the specific examples you used end up receiving too much attention.

var defaultContextVal: SslContext

template defaultSslContext: SslContext =
  if defaultContextVal.isNil:
    defaultContextVal = newContext()
  defaultContextVal

discard defaultSslContext

I understand there's no "logical" reason for this feature and it's not uniform with the rest of the language. You could just use defaultSslContext() every time instead of defaultSslContext. But sometimes even the tiniest bit of productivity increase goes a long way. I would say the same argument applies to dot operators and the like. It could be that any problems the features bring (like nim-lang/Nim#13063) are easily solveable but we are just too apathetic to fix them, so we remove them. Then it is our fault users don't get the added productivity.

I probably wrote too much in this issue anyway, this is dealing with a really small feature and giving so much background probably also misleads attention.

@Araq
Copy link
Member

Araq commented Jul 20, 2022

I like the proposal but I wonder why you picked .symbol as a name over the more obvious .alias.

@metagn
Copy link
Contributor Author

metagn commented Jul 20, 2022

It's just a placeholder, didn't want to use alias to not conflate with the other alias proposed feature, but now that I think of it symbol is much more confusing. Would really appreciate a good name.

@Araq
Copy link
Member

Araq commented Jul 20, 2022

.alias is a good name :P

metagn added a commit to metagn/Nim that referenced this issue Jul 20, 2022
metagn added a commit to metagn/Nim that referenced this issue Sep 6, 2022
metagn added a commit to metagn/Nim that referenced this issue Nov 26, 2022
metagn added a commit to metagn/Nim that referenced this issue Apr 13, 2023
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 a pull request may close this issue.

3 participants