-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
[superseded] alias: myecho=echo
to alias any symbol
#11822
Conversation
alias
alias
that works with any symbol
I'm already using
Or maybe it is possible to reuse
|
This has lots of issues:
|
Why are aliases bad style? I guess it also depends on the use case. What are situations where you would consider it bad style and where would they be more appropriate? As far as I'm concerned, I was thinking of naming subexpressions, but these extra assignments would probably/hopefully be "optimized away" by the compiler anyway. :-) For the subexpression case a compact syntax would be nice, otherwise I'd probably just accept potentially having an extra copy operation for the subexpression assignment. |
Because you always have to learn them, so if there is
It's pointless cognitive overhead.
Oh, that's a different kind of alias. |
I think aliases can reduce cognitive overhead by not asking you to remember non-important details that tend to vary among langauges. (was it |
Who gets to decide whether two concepts are semantically identical between languages? What if they get it wrong? Why should I have to guess as to whether you've reimplemented something or merely aliased it? I'm not sure how I feel about |
New library features should go to lib/experimental, and new programming language features should only be available when explicitly enabled via compilation flag. |
You've created two PRs that implement the same thing, why don't you make that evident in the title of the PR? or even at the start of your PR text? The current title could be better, and would allow me and others to quickly see what this PR is about. I would name it like this: "Implements
Once again, please write more concisely and more clearly. As far as this PR goes: the |
done, you can now enable the feature via a localized flag:
done, moved to will address other points in a bit |
alias
that works with any symbol:=
operator that can alias any symbol
They're not the same thing:
These have entirely different properties:
I've improved the title. I had mentioned in the 1st sentence that this PR was for aliasing symbols, whereas #11824 was for lvalue expressions. I've reworded a bit, I hope it's clear enough now.
I've improved the title. This PR however is not an alternative to #11824, as explained above.
I moved it to sugar.nim. As I've explained in the top post, it is impossible AFAIK to alias symbols using a pure library solution, so I'm not sure what you mean by I will address remaining points later, notably regarding use cases that are made difficult without this feature |
@dom96 You suggested a syntax
for PR #11824. I think this syntax would make more sense for the feature in this PR. Or even/additionally
similar to In that case, as I understand it, there wouldn't be a need to define a new operator that could conflict with other custom operators. (By the way, I think using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not a fan of introducing new features to the compiler. They always come with new problems that we did not anticipate. But I think to have experimental features that won't interfere with people who don't want to bother with issues of new features they never asked for is ok. And then at a later stage, when we can see for sure that the feature helps real projects without causing too much harm, we can take away the experimental
-ness from them.
On the other hand, when this feature causes lots of problems, that we don't know how to fix, then we should be able to revert to a Nim that does not have this feature.
So, the :=
operator needs to be defined in a new file in lib/experimental
e.g. lib/experimental/aliasop.nim
, not insugar.nim
or any other alread existing file.
Does nim really need this feature? template someAlias(x: varargs[untyped])
theProcOrTemplateToAlias(x) and maybe introduce an |
I am not against the feature per se, but So, if this goes in, I would prefer a different syntax. I like @sschwarzer "alias foo = bar" the best. It seems very Nim-esque syntax to define a new class of thing ( |
I wouldn't say "a lot". I think there's a good overlap in use cases. Although I have missed a cheap way of aliasing sub-expression (i. e. without making a copy) in Nim, I nonetheless agree that adding such an aliasing feature may not be worth the extra complexity. It may not be much, but a dozen small simple features can sum up and unnecessarily complicate the language. This reminds me of another ticket, #8306. I think keyword-only arguments in Python make sense and I use them occasionally in my code, on the other hand I liked the IMHO pragmatic decision not to add them to Nim. For what it's worth, here the PEP about named sub-expressions for some more background: |
(Non-exported) aliases can be useful in implementations for reducing repetitive, lengthy identifiers down to size. I'm not really a huge fan of aliases as generalized "API convenience utilities" like others have suggested, e.g. I agree that it should be a keyword (i.e. |
Right, what confused me is that you spend a lot of your time comparing |
Aliases are amazing, but I will once again repeat the Nim mantra:
This is yet another feature that grows the language core which could be implemented using macros (perhaps with some gotchas, but you can get to a pretty good implementation and I bet you can even fix those gotchas with some clever coding). For someone who's dreamt up this mantra I'm disappointed @Araq isn't enforcing it more often. Nim doesn't need more features such as this, it needs less. Please consider using your time to remove things like the do notation or other features in the experimental manual which should be killed. @timotheecour I'm not going to close this PR, but I suggest strongly that you do. You will spend time going through the remarks people leave here and then this PR won't be merged anyway. |
Ironically, I also used the word "alias" - and I used it with a different meaning than suggested in this ticket because it was "obvious" to me what "alias" meant. :-D |
:=
operator that can alias any symbolalias: myecho=echo
to alias any symbol
PTAL:
alias: myecho = echo # alias for symbol (this PR)
byRef: foo2 = x[1].baz # ref for lvalue expression (#11824) which also makes the syntax more symmetric between
that's just not true. This feature request keeps popping up, see links I've added in top PR post |
@timotheecour Thanks a lot for the additional clarifications! Nonetheless I can't help it to add a remark on "aliases" in Python (which you mention in the ticket description). The usual form of "aliasing" in Python is just an assignment: new_name = some_expression
# Use `new_name` instead of `some_expression`.
... Example: some_list = [1, 2, 3]
new_name = some_list
# `some_list` and `new_name` refer to the same list object,
# so `some_list` gets `4` added.
new_name.append(4) On the other hand, this doesn't work as you may expect: some_list = [1, 2, 3]
new_name = some_list
# This creates a new list and assigns it to `new_name`.
# `some_list` isn't modified.
new_name = [4, 5] (For details, see this talk, slides 8 and later, but things can get more complicated if customized attribute access is involved.) The new I think conflating this Python semantics of "alias" with other semantics illustrates what I said above about "obvious" high-level concepts vs. subtle semantic differences. Just to be clear, I'm not saying it would be the end of the world if Nim used the word |
modeling There is no conflation or confusion possible here,
this ref/alias distinction uses (AFAIK) the same semantics as in D and some other languages (see note in top post); some language's semantics will defer, obviously, but I'm defining here the alias semantic that IMO makes the most sense for nim. |
I didn't intend to suggest modeling Nim's semantics after Python. I added the comment because you mentioned Python as an example of a language with aliasing, and my point was that the "aliasing" in Python is only used/mentioned informally as such and it's quite limited and has possibly surprising behavior if you think of an assignment as "aliasing".
Again, I didn't want to suggest any particular semantics of aliases. My point was more "meta", about different meanings of "alias" and possible misunderstandings for users of the language. I do appreciate that you make a clear distinction between aliasing of isolated symbols vs. lvalues/refs. 👍 |
my other PR #11992 is more general and supersedes this one, making every symbol 1st class (in particular, templates/(inline)iterators/etc can be passed to other routines (procs/iterators/etc)); and defines lambdas and aliases as a by product. I'll keep it open until the other one gets merged (but if really needed I can close this one in the meantime) |
alias: myecho=echo
to alias any symbolalias: myecho=echo
to alias any symbol
I'm closing this one in favor of that one. |
[EDIT] nim now has a way to alias any symbol (for lvalue expressions, see #11824 instead), for example
alias: myecho=echo
.This has been an often requested feature, found in other languages eg D's
alias
(or to some extend C'sdefine
)see extensive unittests in tests/magics/talias.nim
alias:r=result
works just fine)fixes
alias
avoids the issues mentioned in Internal compiler error for proc alias #8935:alias:testForMe=assert
works,alias:myPuts=system.echo
works, generic/template/macro aliases work etcalias:my_echo=system.echo
workstemplate myalias(args: varargs[untyped]): untyped = echo(args)
didn't work withmyalias()
import foo as bar
)this feature request keeps popping up
examples (see more in tests/magics/talias.nim)
could it have been done without patching the compiler ?
no.
There are many issues making that impossible without this PR, if you're not convinced, try out the test suite I have (for example, aliasing a template/macro with all optional params, iterator, module etc). Using things like
template myalias(args: varargs[untyped]): untyped = myexpr(args)
or more elaborate variants just doesn't work in many situations; eg:template myalias(args: varargs[untyped]): untyped = echo(args); myalias() # fails
;Furthermore, the patch is small and straightforward (essentially just introduces a new magic), and results in essentially no compile time overhead; it really boils down to adding
addInterfaceDecl(c, alias)
, seesemAlias
note
see also #11824 which defines ref for lvalues instead of alias for symbols. Lvalues and symbols should not be conflated as it would lead to ambiguities, hence the 2 different syntax:
use cases
the main use case for
alias
is as described in https://dlang.org/spec/declaration.html: a way to redirect references from one symbol to another(note that
template myecho(args: varargs[untyped]) = echo(args)
won't work, as noted above)assert / doAssert
could've been implemented in a simpler way:this would've avoided the complications due to
instantiationInfo
being affected by intermediate template definition, whichalias
avoids.Another similar scenario is conditional definition, eg
os.quoteShell
which could've been implemented withalias
and avoid intermediate proc + non DRY codenote that
template debug2(args: varargs[untyped]): untyped = debug(args)
would not work, giving CT error.Also note that when implementing an alias via an intermediate template in cases where it does work, it doesn't quite fit as a 1-1 replacement, eg reflection using
macros.owner, macros.getImpl
will produce different results, unlike withalias
(see also note regardinginstantiationInfo
)other use cases:
alias
also allows to avoid symbol clashes while keeping method call syntax, eg when doingditto with turning regular third party procs into operators, eg matrix operations:
how frequent are aliases?
pretty frequent, search in nim code base for
alias
.eg:
this could be rewritten as:
there are many examples of that in nim code, and even more in third party libs.
alias in other languages
(not restricted to types)
alias fooa = bar.foo
use bar::foo as fooa;
#define fooa foo
perfect forwarding
, see https://stackoverflow.com/questions/9864125/c11-how-to-alias-a-functionlet fooa = foo