9 ms·
JEP 325: Switch Expressions
- nikolay 9y agoThis is inconsistent and no longer Java. The -> is not a good idea and break <something> should be return <something>. The -> throw e; "sugar" is just ridiculous!
- SolaDev 9y agoIMO, return <something> may be ambiguous in switch expression.
- nikolay 9y agoYeah, but return gives the value of an expression and break is a control flow keyword.
- Macha 9y ago-> is already in for lambdas.
- nikolay 9y agoYeah, but this is not a function.
- merb 9y agothe only problem/wierdness might happen with -> is if switch will return a lambda. i.e. case "Foo" -> () -> "newfoo" looks silly at first. well scala supports that and it looks strange at first but in functional programming, these patterns aren't as strange as they first look.
- nikolay 9y agoPeople already use return if the switch is the last statement in a function, so, all this "sugar" is only confusing, inconsistent, and not improving the readability or the learning curve.
- merb 9y agowell I think the sugar is fine. just the none sugar is kinda.. wierd. who would ever write: 'case "foo": break 1' it's just unnecessary. (but they probably do it for backwards compat or so, no idea..)
- int_19h 9y agoThey can't use "return", because it already means something else in Java, including inside a switch statement.
- earenndil 9y agobreak <something> should not be return <something>. What if you actually want to return something from within a switch? More to the point, what about existing code that uses return in a switch statement.
- nikolay 9y agoThat would be a terrible coding practice!
- joe_fishfish 9y agoThis looks like a backport of Kotlin's `when` expression.
- dtech 9y agoIs that a bad thing? Also it's much more similar to Scala's "match" expression, which is also on the JVM and predates Kotlin by about 7 years.
- on_and_off 9y agoInteresting to see Java copy modern languages good ideas. The footgun of 'break' in switch statements has always bothered me, I strongly prefer the kotlin/swift way of doing this.
- ajkjk 9y agoThey've been doing that for a long time. Just... slowly.
- tigershark 9y agoSlowly is an euphemism.. Lambda Expressions were introduced in c# in 2007, Anonymous delegates exist in c# since 2005, Java introduced closures in 2014...
- ajkjk 9y agoI didn't mean slowly as a euphemism. It's just slowly. They're extremely methodical about changes to the core language. And, yeah, it's slower than many would like, but they do it right and the language remains stable and reliable. Anyway, Lambda expressions have been around in, like, Lisp for at least 40 years and in mathematics for, what, 80? So everyone's slow by that account.
- tigershark 9y agoI emphasised the “slowly” because c# has the reputation of being “a bad copy of Java”, while apparently the opposite is true given how long it took Java to copy closures and to produce a bad copy of LINQ.
- dtech 9y agoThey want to prevent another half-baked implementation of a feature like they did with generics. C# is much faster and has much more features, but because of that it's also a bit of a mess sometimes. For example regarding closures/anonymous functions it has delegates, lambdas and anonymous (inner) classes which all have overlap but aren't fully the same. Java only has anonymous inner classes, and a convenient syntax and good support for anonymous inner classes with only 1 method (which they call lamdbas)
- pierrebai 9y agoMy view is that this shows again that worse is better. The old form is better because it is awkward and it can only be improved by turning it into a function. Within a function, each switch branch can be a return. Then you get the benefits: * Make the original function shorter. * Give a descriptive name to what you're computing. * Make the computation reusable. It's what I find lacking with lambdas: it makes it too easy to forego good refactoring because it makes too easy to write one-off code that in reality will be rewritten many times in different places.
- tigershark 9y agoNo, worse is worse. Pattern matching is much, much cleaner than a switch with the branches extracted in separate functions. I don’t think that anyone using languages that support proper pattern matching can disagree. If someone is writing the same lambda n times instead of extracting it in a common method the problem is not the lambda function, but the developer. Closures are probably the best feature in Java and they have been delayed enough.
- jjnoakes 9y ago> Pattern matching is much, much cleaner than a switch with the branches extracted in separate functions I don't think that's what is being suggested. I think the suggestion is to move the entire switch statement to a separate function, use 'return' in the switch cases, and have the caller assign the variable once, from the return value of the function.
- neandrake 9y agoRe: lambdas - if one-off code is being rewritten so many times maybe it's small enough that it doesn't warrant it's own function? I've never run into that issue and love to use lambdas where possible -- in fact the use of streams api has frequently been a source of simplifying existing boilerplate loop-type code. Any time lambda code seems to be repetitive and large enough to warrant refactoring that's usually what happens -> throw it into a method and call from the lambda (or just use method reference syntax if possible).
- specialist 9y agoAssignable return values: +1 Concise AND expressions (eg "case UP, DOWN -> 1;"): +1 Using keyword 'break' instead of 'return': -1
- tzahola 9y agoYou mean concise OR expressions, right?
- specialist 9y agoI’m not sure. Reading the JEP, I inferred the separate clauses were the ORs and each clause’s compound expression could have ANDs. But what you say is likely right.
- mikelward 9y ago'break' feels ugly, but doesn't 'return' already have a different meaning here? You could do something context sensitive to make 'return' act differently in a switch expression versus a switch statement, but that seems more confusing.
- earenndil 9y ago> You could do something context sensitive to make 'return' act differently in a switch expression versus a switch statement But you shouldn't. That would break existing code. What if you actually want to return something from within a switch statement?
- mikelward 9y agoYou ignored the parts where I said "already has a different meaning" and "that seems more confusing".
- blt 9y agoGlad to see conditional expressions becoming popular. TBH it's hard for me to understand why anyone ever felt that switch/if should be statements. I guess being too immersed in assembly programming?
- ComputerGuru 9y agoI'm seeing a lot of interest in pattern matching as users that have discovered it via rust's `match` or similar want to benefit from it in $dayjob language. C# has seen a similar push to implement pattern matching, down to the use of `_` as discard. The first iteration of this feature in C# 7 is feature light, but it's a good start, and they've promised more to come. The team behind C# has become really good at getting over NIH and embracing new technologies and techniques while somehow preserving backwards compatibility and ergonomics. Anders Hejlsberg doesn't kid around. Here's an example cribbed from an official MSFT blog [0]: public static int Count<T>(this IEnumerable<T> e) { switch (e) { case ICollection<T> c: return c.Count; case IReadOnlyCollection<T> c: return c.Count; // Matches concurrent collections case IProducerConsumerCollection<T> pc: return pc.Count; // Matches if e is not null case IEnumerable<T> _: return e.Count(); // Default case is handled when e is null default: return 0; } } A lot of people have lamented this as the death of F#, but I think MSFT is making the right calls here. EDIT: Little-known fact: C# actually does have discriminated unions, and has had for a long time (from the start?) in the form of the `Exception` base class. In fact, pattern matching in C# can be "pulled off" (read: hacked together as a proof-of-concept) without the changes from C# 7 by simply using the extended catch syntax: class MyType1 : System.Exception { /* ... */ } class MyType2 : System.Exception { /* ... */ } void foo() { throw something ? new MyType1() : new MyType2(); } void bar() { try { foo() } catch (MyType1 mtype) { //take type-specific action here } catch (MyType2 mtype) { //take type-specific action here } catch (Exception _) { //the _ was optional, but this is the `default` block } } [0]: https://blogs.msdn.microsoft.com/seteplia/2017/10/16/dissecting-the-pattern-matching-in-c-7/ https://blogs.msdn.microsoft.com/seteplia/2017/10/16/dissect...
- loopbit 9y agoI might be wrong, but I'd say that the interest in switch expressions and pattern matching from the Java community most likely comes from Scala (a JVM language) rather than Rust. Here's an example from the Scala docs: def showNotification(notification: Notification): String = { notification match { case Email(email, title, _) => s"You got an email from $email with title: $title" case SMS(number, message) => s"You got an SMS from $number! Message: $message" case VoiceRecording(name, link) => s"you received a Voice Recording from $name! Click the link to hear it: $link" } }
- g7r 9y agoI want this in Go!
- dtech 9y agoDon't count on it. Go decided against if-expressions despite them being much more common, so I don't see pattern-matching-like construction coming to go.
- pjmlp 9y agoGo is a kind of safer C with GC, it won't move much beyond that. Better appreciate it for that, than wishing for features that will never come.
- makecheck 9y agoLanguages shouldn’t try so hard to wrap syntax around one particular use for something, because you end up tearing the whole thing apart in maintenance. It’s sort of optimizing the writing of the code, which isn’t the worst part. Here, “int result = switch...” seems nice for that one situation, “until it isn’t” (and in my experience these “until” events can come as soon as the very next time you have to maintain the thing). Oh, wait: I actually want to log something in one of the cases in addition to the assignment but since the entire thing is a fancy assignment expression now I have to rewrite 90% of it to add a glorified print statement for one of them!? And it’s not just Java. In “new” C++ for instance, the highly-specialized syntax for loop iteration is nice but it has the same problem: sometimes the change you’re making does need iterators, unusual increment points, etc. and you end up peeling apart everything that was supposed to be so helpful and rewriting way more than you should need to.
- TomMarius 9y agoI don't get you. You can still use the old syntax without the arrow and add your print before you break with a value inside a switch expr.
- dragosiulian 9y agoYou probably missed the part below the first paragraph. You can have additional statements in case branches.
- dtech 9y agoYou're completely missing the point. The switch expression is exactly that, an expression. It can be used wherever you can use an expression. This is fundamental to programming languages and especially in functional programming languages where it is a requirement of everything in the language. You can use logging/side effect in it. You can not assign it to a variable, all valid in Java. Consider the if expression (ternary ?: operator in Java). In most modern languages (e.g. Scala, Kotlin, Rust) there is no ternary operator, and only an if-expression: int value = if(something) 1 else 2 According to you, this is wrong, but it isn't, you can still use it as a statement: if(something) { doThis() } else { doThat() } Just like you can have a statement (line) with just "1+1" or "doThis()", you can have a statement of just an if-expression. And you can also add side-effect (logging) withing expressions: int value = if(something) { log("Uh oh"); -1 } else { 1 } Making a language construct an expression is the complete opposite of tying it to a particular use-case, it's giving it the ultimate flexibility because you can use expressions everywhere.
- eecc 9y agoDoh, can’t we have pattern matching - with destructuring of course - and be done with it? (And tuples, ADTs ah the list goes on..)
- dtech 9y agoThere's a separate JEP [1] for pattern matching, and the switch expressions are both preparation, companion and requirement for it. [1]: http://openjdk.java.net/jeps/305 http://openjdk.java.net/jeps/305
- eecc 9y agoNice, I don't see how I could – at the very least - upvote for this proposal. How does that work?
- joncampbelldev 9y agoI must have gone full lisp weenie, because I find it ridiculous when remembering the days of being a happy java dev, waiting years for someone to include a syntactic change in the spec, all whilst crossing my fingers that they will include my use case. Clojure macros have spoiled me with cond, condp and case plus whatever else I or the community come up with. And my half thought out changes are nicely isolated to a single project or library instead of baked into the language for eternity.
- runeks 9y agoGenerally speaking, when a language developer adds really useful, special syntax to a language — that language users cannot define themselves — it seems like a good idea to stop, and consider whether it makes sense to restrict the usefulness of this concept to just this special case. I.e. the Java boolean type, which can only be true or false (and not default). Could it be that there are other valuable uses of this ability, instead of using enums where you always have to handle the default case? Can it really be the case that true/false is the only case where not having to worry about default is extremely helpful?
- joncampbelldev 9y agoI'm sorry, but I'm a little confused by your comment about default cases in reply to mine about syntax extensions being in the hands of language designers vs everyone. I am also a little unsure what you mean by not worrying about default. Even polymorphism has to deal with this, if you call a polymorphic method on an object that doesn't implement that interface you'll get at best a compile problem, at worst a cast exception. This is why some languages provide support for a "default" or "method not implemented" hook in polymorphism. If you are arguing that polymorphism is a better way to build systems than switch/case statements then no argument here. Open constructs like polymorphism are far better for growing and evolving large systems over time. That doesn't mean we should exclude a nice way to say "i've got a variable that i want to translate to some other value in a few different ways". My point was only that it just seems so silly to me that everyone is discussing whether this syntax is "best" or how it "doesn't do X, Y or Z", because I remember doing that too before Rich Hickey (angelic choir noises) showed me that actually you don't have to put up with that shit. Just use a language that puts syntax extension in the hands of it's community and let them figure it out without burdening the core language with a thousand little tradeoffs for the 90% use case.
- stokito 9y agoI don't need this. In most cases everything can be solved with different methods overrided by type. This is OOP way. But it's makes language more complicated and what is more important - it makes harder to refactor, especially via IDE. So my opinition: we don't need this and this doesn't have any value besides marketing.
- nine_k 9y agoThe problem with OOP way is that it's overly wordy and complex in this case. Much like switch statements in procedural code before the advent of OOP. Type-based function overloads are not specific to OOP, by the way.
- based2 9y agohttps://reasonml.github.io/ https://reasonml.github.io/ - When '|' becomes a case. https://docs.scala-lang.org/tour/pattern-matching.html https://docs.scala-lang.org/tour/pattern-matching.html https://antonioleiva.com/when-expression-kotlin/ https://antonioleiva.com/when-expression-kotlin/ https://www.reddit.com/r/java/comments/7rgnei/jep_325_switch_expressions/ https://www.reddit.com/r/java/comments/7rgnei/jep_325_switch...