It'd be convenient to have a designated dummy variable _
(actually keyword), which would simply ignore everything stored into it. For example, you often want to deconstruct tuples like so
a, _, b, _, c = f()
where the _
values are uninteresting. Likewise, one may want to ignore function arguments, like so
function foo(a, _, b, _, c)
return (a, b, c)
end
This is actually a syntax error right now, because two arguments have the same name, which makes sense if you actually want to read their values. The idea here is to instead discard them, and reading the value of _
would be a syntax error.
In theory, this is purely about code readability: when one sees _
, one knows that the value is not used and thus won't need to be thought about any further; OTOH if one sees something else, then the value is probably going to be used further down the line and needs to be kept track of. One also won't need to behold the unsightly output of wetware gensym() implementations in unused function argument names. In practice though, there is also a performance difference with the current compiler:
function f1(x1, x2, x3, x4, x5)
a, _, b, _, c = x1, x2, x3, x4, x5
return (a, b, c)
end
function f2(x1, x2, x3, x4, x5)
return (x1, x3, x5)
end
code_native(f1, (Int, String, Int, Int, Int))
code_native(f2, (Int, String, Int, Int, Int))
The assembly for f2 is significantly shorter.
The use of underscore, _
has been discussed in https://github.com/JuliaLang/julia/issues/837, but not in the context of function arguments.
I would like this a lot. Code gets messy when I don't care about an output variable but have to explicitly reassign nothing
or []
or 0
to it in order to reclaim that memory.
The function _
syntax makes sense when you're implementing an API but don't need all arguments (especially useful for dummy or mock functions).
People already use _ and ignore it. I'm not sure about the utility to enforce further constraints/guarantee of its use/non-use. If performance is critical, and we find ourselves using _ in that context, I wonder if the function generating the unused value is too bloated and should be re-factored.
The code generator can probably be improved for cases where a variable is never used.
For function arguments, you can already use e.g.
f(x, ::Any) = x
to explicitly ignore one.
Perhaps it should be allowed also for assignment locations, e.g.
x, ::Any = f(z)
One thing I like about ::Any
is that it's not a special behavior of a specific identifier, but distinct syntax.
A combination of the improvement to code generation that @JeffBezanson suggests and knowing the trick that @toivoh points out (is it in the manual somewhere?) would probably resolve any of my issues.
I looked into it and I think we already optimize out unused variables. The case described above probably produced the Warning: Returned code may not match what actually runs.
message.
+1 for @toivoh's suggested syntax.
Closing as this is better handled by forms of static analysis, not syntax.
@jakebolewski, is there another issue which tracks the static analysis improvements needed for this? Or would it be better to reopen and change the title (or open another issue)?
Here's one situation where it could be nice to have an explicitly ignored identifier name:
julia> foo() do _, _
println("ignores arguments")
end
ERROR: syntax: function argument names not unique
I'm reopening this, as I've encountered more and more cases where it would be convenient for the front end to be able to emit a pseudo-name for a value that gets ignored.
Example 1: The syntax f(::T) = ...
is pretty widely used, but internally all function arguments need names. We currently use gensyms for this, but that's wasteful --- the symbols have to be stored, and information about them is tracked even though the names are ultimately never used. Unused variables can only be fully optimized out rather late, and until then we're carrying around baggage.
Example 2: On the jb/functions branch all functions are generic functions, so I want to normalize the syntaxes f(x)=x
and x->x
to the same thing as early as possible. It would be convenient to convert the arrow form to _(x)=x
. If there are many closures in a function they wouldn't conflict, since _
never actually gets assigned.
There are a few ways in which the full version of this feature is nicer than relying on optimizations:
_
without an error._
spuriously listed among local variables._
.This also sounds like a better and more general solution to https://github.com/JuliaLang/julia/issues/12474
I'm on board. I guess this would conflict with potentially using _
for terser lambdas, although this is always used in lvalue position, whereas that's always in rvalue position.
That would be a bit confusing. It would be nice to be able to give "error: _ used in value position" errors.
If we allow that, it effectively reserves value position usage of _
, so that's ok either way.
I was thinking the other day to port a PHP MIT licensed version of gettext to Julia, gettext use _
(as seen here) instead of gettext
as a short hand, I would love to have support for something like this in Base (and beyond?) by default allowing Julia to be multilang and also users to be able to make multilang packages.
I don't know what do you think about this? I haven't mentioned anywhere because I haven't even started implemented it yet, but it's one step in my efforts to explore multilang Julia here.
I'm just way too slow, wish I had more time.
+1 for gettext integration, but _
should probably not be defined by default, as it is currently used for values you don't care about. As regards licensing issues, porting the MIT PHP gettext (I guess you mean this one?) will take a lot of work and be a maintenance burden in the future. I'd rather see how far we can get using NetBSD's libintl, which should work except for the most recent gettext features.
@nalimilan yes I was talking about that PHP implementation, it's the only MIT licensed one I found which looked self contained. I'll experiment with libintl
. I'm not an expert in this so I would really appreciate a lot if you could drop by anytime you want at Julia-i18n chat room if you like and share more of your thoughts.
Thanks for your advice!
Actually Gettext
uses @__str
macro!
using Gettext
bindtextdomain("sample", "po/")
textdomain("sample")
println(_"Hello, world!")
I wonder about it's performance.
The non-standard string literall _""
sounds like a good solution. I don't have much more advice to give, as I don't know libintl at all. I'd simply try to wrap it and see whether you can replicate enough of the features offered by Gettext.jl.
Thank you, I'll try to do that.
it seems most of the goals of https://github.com/JuliaLang/julia/issues/9343#issuecomment-163031697 were implemented (via the hidden symbol '#unused#') in jb/functions (and improved upon in jb/linear3)
Following on @vtjnash's comment, for f -> x, y, z
does this work? ##, ##, z = f()
. Conversely, why not just index the function's output, say z = f()[3]
?
If we're going to do this then perhaps using _
as an r-value should become a syntax error?
yes
(remove "won't fix" label?)
Then the first steps for 0.6 are:
_
as an r-value_
multiple without warning (i.e. implement #18251)This allows people to start using _
as a dummy variable in 0.6. It will still hold a value, which means that code using it won't break 鈥撀爄t will just cause a warning (unless deprecations are off). Then in 1.0 it can be changed to discard assigned values entirely and using it as an r-value will be an error.
Do we really need to go through that kind of deprecation cycle for this? I suspect very few people are using _
in a way that would be incompatible with this change and for those that are, there is a few clear change that can be made to fix it.
Sure, we could skip the deprecation cycle and just make it an error right away.
As mentioned in #20446, another possible use of _
would be as a wildcard in things like Array{_,3}
It'd be nice for f(a, _, c)
_
function arguments, to actually lower to @nospecialize(_)
.
Most helpful comment
It'd be nice for
f(a, _, c)
_
function arguments, to actually lower to@nospecialize(_)
.