Godot: `match` pattern and using `_` as a wildcard

Created on 18 Jan 2017  路  15Comments  路  Source: godotengine/godot

6593

I've done some shallow research on the subject. A few cases were mentioned of _ being used as a wildcard being the idiomatic way to do a wildcard match.

Haskell wildcard patterns use _ for wildcards[1]. However, a valid Haskell variable name must begin with a lowercase[2].
Scala also uses _ as a wildcard[1]. Scala uses the _ for more than just pattern matching[2].
Elm uses _ in pattern matching as a wildcard that is not going to be used. It uses a lowercase 'tags' to match anything if you want to use the value[1]
Racket, as far as I can tell, uses _ as a placeholder variable name, but I couldn't find any reference to it being a symbol especially restricted to wildcards or wildcards being restricted to using _[1]
F#, uses _ as a wildcard pattern[1],
OCaml uses _ as a wildcard pattern[1]
Rust uses _ as a wildcard pattern[1]

Two options, make _ an invalid variable name or use something else for wildcards in the GDscript's match pattern.

There's also the chance that whatever we use as a wildcard here could be used in other places in the future. I'd prefer it if we used * since it could also be used if GDscript ever got argument list like in python (I'm not aware of whether this is implemented or will ever be)

I want to start a discussion around this, because I believe this can decide the future direction of the language.

discussion gdscript

Most helpful comment

Given that there are a few nearly equally good ideas (IMO), I guess we might use some voting..

Use :smile: for keeping _ as wildcard and removing it as a valid identifier (things like _data would remain valid though)

Use :tada: for switching to * and keeping _ as a valid identifier

Use :heart: for changing _ to some other valid identifier, and keeping _ as a valid identifier (e.g. using any or something else..)

Use :-1: for something else (but probably explain what you think would be better, or what is bad with those three.)

All 15 comments

Context: name clashing can occur.

var _ = 42
match x:
    _: print("is it 42 or anything?")

Third option: remove variable patterns and make every identifier a binding. This way it's obvious that _ isn't there to be matched against but to indicate a wildcard pattern.

edit:

variable patterns were introduced to match on constants but since constants are just variables there's no way to read the value of them at parse time.

Removing variable patterns makes the syntax cleaner but you'd need to use "guards" (ifs and continues in the branch's body). So it takes away a convenience but bypasses the name clash.

So something like this wouldn't be possible

match typeof(x):
    TYPE_STRING: print("It's a string!")
    TYPE_FLOAT:  print("It's a float!")
    _:           print("It's something else!")

These "constants" are actually just regular variables so theoretically a new identifier would be bound.
To use a match on constants I introduced these variable patterns.

There should be another way to match on constants or constants must be identifiable at parse time.

Given that there are a few nearly equally good ideas (IMO), I guess we might use some voting..

Use :smile: for keeping _ as wildcard and removing it as a valid identifier (things like _data would remain valid though)

Use :tada: for switching to * and keeping _ as a valid identifier

Use :heart: for changing _ to some other valid identifier, and keeping _ as a valid identifier (e.g. using any or something else..)

Use :-1: for something else (but probably explain what you think would be better, or what is bad with those three.)

An example of how this could work

# *arg
match foo:
    [*, *a, *b, 2, ..]: print(a,b); continue
    *x: print(x); continue
    *: print('meh')

I think keeping things simple and saying "godot is using regex (or posix) style for all wildcards" is a better option. So :

match foo:
    [*, a, b, 2, ..]: print(a,b); continue
    x: print(x); continue
    *: print('meh')

is good for pattern matching IMO.

Combination of pattern matching with argument-list seemed confusing to me.

Pattern matching is different from regex, I wouldn't like to mix those syntaxes.

Regex operates on strings, pattern matching uses "the shape" of data structures to branch. {, } and [,] have fundamentally different meanings in this case.

If we do it with regex style then we're the only one in the gang of languages that support pattern matching who goes against the convention.
Using anything different from _ is like making if behave like while. You'd know about it but every other language uses a convention that is different from yours.

I'm open for discussion, but I don't really see a point in using anything different than _ and if we do it shouldn't call itself pattern matching because it would just go against the norm.


My opinon: either _ or no pattern matching.

edit: I'm fine with dumbing it down and making it a simple switch, but I don't want GDScript to become the "special care kid"

For me this is settled. _ is the standard for a pattern matching wildcard. Wanting to use it as a variable identifier and being annoyed by the shadowing is wanting to write illegible code. Just name your temporary variables tmp and all is good :)

So let's just make _ an illegal identifier for variables (of course not _whatever as @bojidar-bg mentioned) and all is good in the best of worlds :)

# *arg
match foo:
    [*, *a, *b, 2, ..]: print(a,b); continue
    *x: print(x); continue
    *: print('meh')

compared to the current implementation:

# _ wildcard
match foo:
    [_, var a, var b, 2, ..]: print(a,b); continue
    var x: print(x); continue
    _: print('meh')

which does things in two different ways _ var x

If we're going this way, what's that weird .. that comes from functional languages? Eeeeek ;)

We discussed the wildcard pattern in #6593, you can read up the thoughts there. We had the suggestion of nomatch:, of else: and yet we settled with _.

The shadowing of a valid identifier _ is a concern, but then please let's discuss the shadowing problem and not something that already has been discussed before. We thought about it, we discussed and the majority was pro-_, so let's please bury the wildcard problem and tackle the resulting shadowing problem.

I already submitted a fix, if you want to discuss if _ should be a valid identifier then please do that, but don't open a new issue for something that could be discussed in the proposal.

I'm not saying it's set in stone but there are reasons for the way it was implemented. Please read the whole discussion and add you opinions there, but this isn't the place for that IMO.

match foo:
    var _: continue  # is equivalent to `_`
    _: pass # is equivalent to `var _`

So why force this through, even though there are non-breaking ways to do it already.

@ClikCode because it's ambigous. And it doesn't fix the original problem of the pattern shadowing a variable.

Ok, seems like both other contributors and voters are decided that they want _ to stay, so I guess that's decided now :confused:

@bojidar-bg :
Actually, given the current poll results ( 馃憥 1 馃槅 7 馃帀 5 鉂わ笍 3 ), and ignoring your votes on each items ( 馃憥 0 馃槅 6 馃帀 4 鉂わ笍 2 ), we could say that 100% voters wants _ to stay ... ( 50% as wildcard, and 50% as valid identifier )

@SuperUserNameMan Yeah, I misworded my last comment. I meant to say as-is, or to stay as a wildcard
.

Anyway, case closed by vote, discussion and inactivity. I see no use in keeping this issue alive, especially after #7599 was opened to discuss more uses for the new token :smiley:

Was this page helpful?
0 / 5 - 0 ratings