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

Dummy variable _ #9343

Closed
RauliRuohonen opened this issue Dec 13, 2014 · 32 comments
Closed

Dummy variable _ #9343

RauliRuohonen opened this issue Dec 13, 2014 · 32 comments

Comments

@RauliRuohonen
Copy link

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.

@ivarne
Copy link
Member

ivarne commented Dec 13, 2014

The use of underscore, _ has been discussed in #837, but not in the context of function arguments.

@iamed2
Copy link
Contributor

iamed2 commented Dec 13, 2014

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).

@tonyhffong
Copy link

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.

@JeffBezanson
Copy link
Member

The code generator can probably be improved for cases where a variable is never used.

@toivoh
Copy link
Contributor

toivoh commented Dec 14, 2014

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.

@iamed2
Copy link
Contributor

iamed2 commented Dec 14, 2014

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.

@JeffBezanson
Copy link
Member

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.

JeffBezanson added a commit that referenced this issue Dec 15, 2014
…9343)

this builds and passes tests with LLVM assertions, but we should be
on the lookout for regressions here.
@ArchRobison
Copy link
Contributor

+1 for @toivoh's suggested syntax.

@jakebolewski
Copy link
Member

Closing as this is better handled by forms of static analysis, not syntax.

@kmsquire
Copy link
Member

kmsquire commented Jun 2, 2015

@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)?

@StefanKarpinski
Copy link
Member

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

@JeffBezanson JeffBezanson reopened this Dec 8, 2015
@JeffBezanson
Copy link
Member

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:

  1. As already pointed out, you could have multiple function arguments called _ without an error.
  2. When debugging you would not see _ spuriously listed among local variables.
  3. Removing stuff as early as possible makes the compiler more efficient.
  4. Static analyzers would know to ignore e.g. assigning values of different types to _.

@yuyichao
Copy link
Contributor

yuyichao commented Dec 8, 2015

This also sounds like a better and more general solution to #12474

@StefanKarpinski
Copy link
Member

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.

@JeffBezanson
Copy link
Member

That would be a bit confusing. It would be nice to be able to give "error: _ used in value position" errors.

@StefanKarpinski
Copy link
Member

If we allow that, it effectively reserves value position usage of _, so that's ok either way.

@Ismael-VC
Copy link
Contributor

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.

@nalimilan
Copy link
Member

+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.

@Ismael-VC
Copy link
Contributor

@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!

@Ismael-VC
Copy link
Contributor

Actually Gettext uses @__str macro!

using Gettext

bindtextdomain("sample", "po/")
textdomain("sample")

println(_"Hello, world!")

I wonder about it's performance.

@nalimilan
Copy link
Member

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.

@Ismael-VC
Copy link
Contributor

Thank you, I'll try to do that.

@vtjnash vtjnash added the won't change Indicates that work won't continue on an issue or pull request label Mar 25, 2016
@vtjnash
Copy link
Member

vtjnash commented Mar 25, 2016

it seems most of the goals of #9343 (comment) were implemented (via the hidden symbol '#unused#') in jb/functions (and improved upon in jb/linear3)

@vtjnash vtjnash closed this as completed Mar 25, 2016
@SrAceves
Copy link

SrAceves commented Sep 3, 2016

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]?

@StefanKarpinski
Copy link
Member

If we're going to do this then perhaps using _ as an r-value should become a syntax error?

@Keno
Copy link
Member

Keno commented Oct 13, 2016

yes

@mauro3
Copy link
Contributor

mauro3 commented Oct 13, 2016

(remove "won't fix" label?)

@Keno Keno removed the won't change Indicates that work won't continue on an issue or pull request label Oct 13, 2016
@StefanKarpinski
Copy link
Member

Then the first steps for 0.6 are:

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 – it 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.

@Keno
Copy link
Member

Keno commented Oct 13, 2016

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.

@StefanKarpinski
Copy link
Member

Sure, we could skip the deprecation cycle and just make it an error right away.

@stevengj
Copy link
Member

stevengj commented Feb 7, 2017

As mentioned in #20446, another possible use of _ would be as a wildcard in things like Array{_,3}

@quinnj
Copy link
Member

quinnj commented Aug 2, 2018

It'd be nice for f(a, _, c) _ function arguments, to actually lower to @nospecialize(_).

JeffBezanson added a commit that referenced this issue Aug 2, 2018
closes #9343
fixes #20931

apply nospecialize to unused/underscore arguments
JeffBezanson added a commit that referenced this issue Aug 3, 2018
alyst pushed a commit to alyst/julia that referenced this issue Aug 9, 2018
KristofferC pushed a commit that referenced this issue Feb 11, 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

No branches or pull requests