-
Notifications
You must be signed in to change notification settings - Fork 18k
proposal: Go 2: add match statement #44022
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
Comments
Please fill out https://github.com/golang/proposal/blob/master/go2-language-changes.md when proposing language changes |
@seankhliao ok.
I really like the simplicity and powerful of Go, but the ability crash on "null pointer" is push me away. Right now I want use Golang and want make more usually for me language items liek protection in language
I meet with Assembler ( Intel ), Ada, Basic, C, C--, C++, Delphi, ECMAScript, Java, Lisp, Lua, Modula, Pascal, PHP, PostSript, Prolog, Python, Rust, Swift, SQL, TeX, Vala.
I think that match is similar to understand like switch.
I think it could be discusses somewher, but quick search does not provide such a proposal.
The flow control syntax can be used by all developers in the language and no restrictions.
Add match statement and provide more compact control flow syntax.
Original post provide two source code example.
I think this may take article about flow control constructs will add new one statment
If you want to process more complex case processing, then you can use the match statemnt expression.
Yes.
N/A
See original message.
I'm not a pro at estimating the cost of language changes.
At the option each one of developer. Use match pattern is optional construction.
Every match want to use additional variable scope, every pattern is want to have local variable name.
Every match case amy take a more than one comparision and may take
No, sorry.
No, sorry.
Actually I think you add some additional PEG grammar and make AST processing.
No overlapping.
No in term of computing.
Yep. match may catch unhandled variant / cases.
No. |
Can you write down the precise semantics that you are proposing? Why introduce a brand new syntax like Why require a brace-enclosed block when the What are the exact semantics of More generally, what big advantage do we get from |
@ianlancetaylor response as follow:
You asking pattern match statement EBNF?
At match body we should separate the pattern from the lambda function being executed and here you need some kind of separator in switch you use keywork "case". Main problem case on my option in Python syntax and Assembler symantics with non clear internal logic (i.e. using break in C and falltruth keyword in Golang). Brace-enclosed provide strict execution range and provide make "match" retun value. I does not know if it possible write some like:
Brace-enclosed provide human intuituve and well known variable scope and provide execution block bounds.
It make switch more complcated language unit and match look like more simple to understanding.
Actually I think that ".." is advanced math feature. Let's talk about this idea later.
I suspect that switch statement may cased only one arguemnt, which requires building a lot of forest for switch checks. Of course, you can refactor the code and create more and more related functions with switch, but it create more and more line of code. For example, in original message check structure two variable at same time. |
See also #40353 for multivalue switch |
No, that is the syntax. I'm asking for the precise semantics. What precisely does it mean? |
I'm sorry, but this is not a good argument. The |
We moved from the language syntax advantages of match structure (explicit scoping, parallel case handling, more explicit execution block) to political reasons (historical). This is a completely different conversation in new mindset space. I think that world already have more spartan language, remember the Assembler with direct cmp and jmp and I don't see much desire to use it today. I know that Golang community declare newcome welcome (i.e. learning simplicity) and at the same time have a unclear structure in the language guarded by historical reasons. Today is a great moment to annonce new language structure and Go 2 sounds like revolution as Python 2 and 3, Perl 5 and 6 and other large language changes. Another part of you argument is classical ad hominem political argument. |
Sorry to jump in, but I think some misunderstanding is brewing here. so let's stay calm and focus at the issue at hand. I think what @vit1251 is proposing is the classic "pattern matching" feature which is present in many contemporary programming languages, often even in conjunction with a switch statement. For example Switch has both switch and match statements, (https://docs.swift.org/swift-book/ReferenceManual/Patterns.html), while C# has extended their if and switch statements to support pattern matching (https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching). In these examples, the switch and the pattern match feature are significantly different, the one is not another way to write the other. So, when asking for what semantics are being proposed, we can look at these existing implementations of pattern matching and consider which of those could have semantics that are for inclusion in Go. Syntactical considerations come in later. I am also jumping in because pattern matching is quite a popular programming feature nowadays, and I think we should at least consider whether or not they should be added to Go and if not, why, and perhaps even add a FAQ to that extent. Pattern match semantics might also help solving certain issues around type switches and generics, or type switches and the proposed union types. With a pattern match we could statically match not only an exact type but also similar types that match the pattern. |
How is that different from type assertions and type switches? In C#, there's an if v, ok := v.(someType); ok {
// No magic required.
} Similarly, you can use a type switch for pretty much the same thing but with multiple branches: switch v := v.(type) {
case int:
// In this case, v is an int.
println(v + 2)
case fmt.Stringer:
// Works fine with interfaces automatically, too.
println(v.String())
default:
// This works just fine, too.
doSomething(v)
} |
@vit1251 I am not making an ad hominem argument. Also, citing the historical development of the language is not making a political argument. For better or for worse, it is extremely unlikely that we Go will ever significantly break backward compatibility. See https://go.googlesource.com/proposal/+/refs/heads/master/design/28221-go2-transitions.md . |
Your write "Perhaps you don't like the way it works, ... people are accustomed to it". I see here "you" and "like" and "people" as result I feel that argument to my personal preferences between people. You weight my preferences with historical reasons. It argument definitely ad hominem. To be more precise, here is a variant: Argumentum ad populum ( ... most people walk street on red signal and it right ).
Please watch on argument "... by hisorical reasons" from another side. Today we have a large count of experience by resolve errors in past ( .. by definition of expirience ). But people contain a an amazing feature to continue improves. Once we were young and did not know how to walk, but today we runing and jumping. Is the historical argument constituted an excuse for stay as children?
I don't quite understand why you talk about breaking backward compatibility. I talk about implement match as new one structure like threnary operator and you may already save "switch" as improve option for "if" and they all overlaps semantics. If "switch" little better than "if" why you prevent to resolve "switch" problems in new one construction? Resume: I understand your argument as most people are used to the flaws of "switch", but in the next big promise to improve the language these problems will not be solved or improves. |
Introducing a new keyword breaks backward compatibility. Match as a new key word is not possible because some people are now using the word "match" as a variable name. But there are other ways to get match semantics. It would be possible to enhance the current switch statement with the semantics you want, for examples by using two key words in a way that is not allowed now (e.g., "switch range") in such a way that it is backwards compatible, or perhaps with built-in functions. @DeedleFake, Pattern matching generally allows not to match a single type but also ranges of types, sometimes with wildcards (looking as some functional languages). Especially when using a type switch in conjunction with generic types, this could be handy. |
@vit1251 Thanks for the reply. I won't continue the exchange as it seems unlikely to be productive. Let me just say two things as clearly as I can. First, if we add a new language construct that is similar to Second, you must document the precise semantics of the new language construct. You have not done so. Thanks. |
Perhaps this is another kind of unsolved problem - impossibility to extending. Computer language may provide some mechanisms for extending and enable addtional language features. Example:
If you have motivation to solve, then you could be found solution.
In this case does not resolving problem with variable scope and syntax overload.
At the initial stage, we encountered a gap that there is simply no way to expand the language with new constructions: keywords and arrows. Let's again watch simple example:
An result boolean variable initialize by pattern match expression and step-by-step check with pattern until first match. In this case When you want to implement some sort "falltruth" behavior it possible by use underscore "_" as universal value. Let's on first version look at this variant (without range ".." and another one advanced pattern match feature). |
This seems like a large number of changes, almost all of which introduce patterns that are completely different from any existing Go structures, for what is essentially a very light syntax sugar variant of a |
Hmmm, well if those are the semantics you want, you can already do that with a different syntax: https://play.golang.org/p/Q_iv2EGmB3Z package main
import (
"fmt"
)
func main() {
var original bool = false
var number int = 5
var newNumber int = 0
var result bool = func(b bool, i int) bool {
switch {
case !b && i == 1:
return true
case b:
newNumber = 5
return false
default:
return false
}
}(original, number)
fmt.Printf("%d %d %v\n", number, newNumber, result)
} Admittedly, the anonymous func is needed to introduce a new scope, and the call of that function with (original, number) is somewhat unclear because it after the body of the anonymous function. But there are other issues about defining anonymous functions more easily. For this feature a bit more ambitious semantics would be needed, not just syntactic sugar. |
You rewrite code to avoid intuitive unclean situation. Let's I return back more intuitive unclean situations in your code: var original bool = false
var number int = 5
var newNumber int = 0
var result bool = func(b bool, i int) bool {
switch {
case !b && i == 1:
return true
case b:
var newNumber int = 5
falltruth
case b == 3:
newNumber = 10
default:
return false
}
}(original, number)
fmt.Printf("%d %d %v\n", number, newNumber, result)
} It is clear that you can always rewrite or refactor the source code in accordance with the rules of the language, My point is switch create sub-scopes without brackets and it alient syntax (i.e. Pyhton syntax) in Golang in switch statement. When we meet lexical brace in "switch {" we intuitive await new switch variable scope like we await it between "if !b {" and "}". But actually every case provide new one and in a "falltruth" situation it's continue worsen. Let's little rewrite source code to mark scopes by lexical braces (i.e. since that time it stay more similar to proposal match design): switch {
case !b && i == 1 {
var newNumber int = 5
return true
}
} Actually does not matter switch or match and case or => we use when you return back lexical scope brackets switch stay overdesign at "if" construction and it create anoter one question about what mean bracket on switch it create new scope or provide group. For group in Golang in import use parentheses. I talk about intuitive language design and most people right it sounds like sugar as an any language over Assembler. |
So your point is more about the syntax of the current switch statement? The switch syntax of Go was taken by and large from the C/C++/Java family of languages, but then enhanced with more capabilities in the cases. but yes, in Go, every case statement introduces a new scope for variables, and you consider that counter-intuitive because there are no braces to signal that? It is still possible to use braces to do that, although the fallthrough statement will have to come after, a bit like this: package main
import "fmt"
func main() {
var original bool = false
var number int = 5
var newNumber int = 0
var result bool = func(b bool, i int) bool {
switch {
case !b && i == 1: {
return true
}
case b: {
newNumber = 5
}
fallthrough
case i == 3: {
newNumber = 10
}
fallthrough
default:
return false
}
}(original, number)
fmt.Printf("%d %d %v\n", number, newNumber, result)
} Actually, I think that on the level of the lexer/parser, allowing the syntax of starting the body of a case with a { in stead of a : and ending it with a } would certainly be possible, because it produces a syntax error now (syntax error: unexpected {, expecting :), so changing that would be backwards compatible. The matter though, is then if such a small syntax changes is worth the effort, especially for the Go programmers who will have to read this code, and now will find that there are two ways in which you can write a case statement in stead of one. After 10 years of programming Go, the current Go syntax has become intuitive for me. It seems you are relatively new to Go, so I would say it takes some time to get used to, like anything new really. |
This is because you are using an |
The proposal review committee appreciates the fact that the author prefers to use "flow-control syntax", but it's also straight-forward (if perhaps less elegant and less compact) to achieve the same result using existing Go mechanisms. Any language addition needs to be considered in light of existing Go: not only should it (ideally) fit well with the existing language, but it also should provide a significant functional benefit not easily achieved (or impossible to achieve) with the existing language. The proposed change suggests a language feature that is quite different in style from what we have, and doesn't really provide a significant functional benefit. There's ways to write the equivalent code and those alternatives seem adequate. Finally, the fact that other languages provide mechanisms similar to the one suggested, or that other languages have a mechanism for extending the language does not mean that Go need to do the same. Based on the discussion above, and the lack of strong support in the emoji voting, this is a likely decline. Leaving open for four weeks for final comments. |
I've been trying to see if someone has already talked about it but I can seem to find it, so please let me know if this has already been discussed! I think one of the good things pointed out in this I know the idea behind Go is to have a simple language that doesn't need to be copying others, but there are some really good functional practices that can shorten code by a lot, while also making it more clear. For example: var x = if someVar > 0 {
"String A"
} else {
"String B"
}
var z = switch someVar {
case 1:
"something"
case 2:
"something 2"
default:
"oops"
} I know you could do this, which is very similar. var x string
if someVar > 0 {
x = "String A"
} else {
x = "String B"
} However this can become tedious in some cases where you have a I find this to be very practical in the languages that support it, and I don't think this would be a breaking change either, but rather just an extension of This is not a must by any means and I can happily live without it, but I'd like to know if this has ever been a point of discussion. Thanks! |
@nferrario Your suggestion has come up before, at the very least in the form of a ":?" operator. It has been a point of discussion before. There are lots of constructs in other languages that may be very practical. That is not a strong reason for including such constructs in Go, especially if there are alternatives available that are almost equivalent. |
@nferrario As @griesemer says, there are alternatives available. Just to explain how, you can already do this at the cost of defining closures like this: https://play.golang.org/p/Wgo_YIBkvBB package main
import (
"fmt"
)
func main() {
someVar := 1
z := func() string {
switch someVar {
case 1:
return "something"
case 2:
return "something 2"
default:
return "oops"
}
}()
x := func() string {
if someVar > 0 {
return "String A"
} else {
return "String B"
}
}()
fmt.Printf("Hello, %s %s\n", x, z)
} This example is a bit artificial, but it might be useful to do it like this, since it allows the closures to be factored out later as separate functions. |
Thank you @griesemer and @beoran. Yes I know we can easily solve it using closures and it's not a terrible solution either. It's just a little bit of code after all. But I don't also see a strong reason NOT to include such functional features. It's a nice to have that's useful, and it also avoids having a funcion call. I'm all in on keeping Go simple, I love the way it is and I wouldn't like it to become like other languages like Scala, where you have 5 different ways of writing the same thing. But I do believe we could be a little bit more flexible and allow/include more things. I've seen people saying they don't wanna use |
@nferrario With generics, we can implement the ?: operator very easily ourselves as a generic function, if you excuse my use of Canadian Aboriginal Characters: package main
import (
"fmt"
)
func ᕈ[T any](b bool, ifTrue T, ifFalse T) T {
if b {
return ifTrue
}
return ifFalse
}
func main() {
i := 7
v := ᕈ(i > 5, "greater", "lesser")
l := ᕈ(i > 5, 5, i)
fmt.Println("i > 5?", v, l)
} In fact, I like this so much that on the 1st of April 🤡 I will propose to make ᕈ a build-in generic function , then we can from now on say that yes, we do have ?: in Go language 😉 . Seriously though, if this would be in generics package the name would likely to be gen.if, but this example does go to show that generics will be powerful enough to handle the ?: use case. As for the match, I'll leave that as an exercise for the readers. |
@beoran lol no, that'd be terrible, no doubts! But that's a very good explanation since I wasn't aware we coule achieve such things with Generics. Thanks! |
The usual name for |
No change in consensus since #44022 (comment). |
The current state
Using "switch" provide torn syntax, reuse parent scope, may process part cases.
Problem statement
Source code with "switch" provide simple case processing.
Proposal
Using match statemtnt without destructurization:
Example:
There we have new variable scope, ability to checking all variants is checks, return value, more uniform syntax.
Using match expression:
The text was updated successfully, but these errors were encountered: