22 ms·
The matching syntax looks really good to me: // Java 21 if (obj instanceof Point(int x, int y)) { System.out.println(x+y); } // Older
by jph 3y ago
The matching syntax looks really good to me:
// Java 21
if (obj instanceof Point(int x, int y)) {
System.out.println(x+y);
}
// Older Java
if (obj instanceof Point p) {
int x = p.x();
int y = p.y();
System.out.println(x+y);
}
- riku_iki 3y agoIts not substantial improvement, but another invariant which need to be learned and adds more brain load. I hope someone will design some jvm SimpleLang eventually, which will have very few syntactic constructions but cover all/most of use cases.
- nkh 3y agoIsn't that Clojure? (let [p obj] (if (instance? Point p) (let [x (.x p) y (.y p)] (println (+ x y))))
- riku_iki 3y agoI think Clojure is not statically typed? which is a big disadvantage, and also syntax is very different from current mainstream languages, so even more effort to learn is required.
- nkh 3y agoWhen type checking is needed, I find the Truss library* does the trick quite well. As for the syntax, there is very little, which can make it a harder lift but once you have the hang of it you won't deal with the issues identified in the parent comment. * https://github.com/taoensso/truss https://github.com/taoensso/truss
- The_Colonel 3y agoI don't know what Truss is, but I know that I inherited a few smaller Clojure projects / services, and it's untyped hell. Having optional typing means most people are not going to use it.
- cutler 3y agoJS and Python are not statically typed, or PHP for that matter, but it hasn't stopped JS and Python topping the popularity list year on year nor did PHP stop Facebook from world domination.
- riku_iki 3y agoI think in all cases it was realized that static types are adding significant benefits, so they were added to python, typescript and hack have been developed.
- cutler 3y agoJS and Python have gradual, not static typing. Same for PHP 8 but Hack is a different language.
- deleted 3y ago[deleted]
- Per_Bothner 3y agoOr Kawa: (if (? p::Point obj) (... p:x p:y)) This succeeds if obj matches the pattern p::Point, declaring p to be the value of obj coerced to a Point. This is integrated with Kawa's static type-checking/inference. https://www.gnu.org/software/kawa/Conditionals.html https://www.gnu.org/software/kawa/Conditionals.html
- cutler 3y agoClojure to the rescue ... again. Honestly, I can't fathom why Clojure isn't up there with the most popular languages. Paul Graham was right when he described it, well Lisp, as a secret weapon.
- chii 3y agoi would imagine the idiomatic clojure to do this is to convert the `p` into a bean using `clojure.core/bean` but if it is a java record class, then there's currently no standard library way, since it's not a bean (getter/setter naming of properties). You'd have to write custom code for it, which sucks.
- kazinator 3y agoTXR Lisp: Using quasiquote-style pattern: (if-match ^#S(point x ,x y ,y) obj (prinl (+ x y)) Or using @(struct ...) pattern operator: (if-match @(struct point x @x y @y) obj (prinl (+ x y)) All done with macros. Expansion, compilation, disassembly: 4> (flow '(if-match @(struct point x @x y @y) (new (point 1 2)) (prinl (+ x y))) expand prinl compile-toplevel disassemble) (let ((#:g0062 (struct-from-args 'point 1 2))) (let* (#:result-0065 x y) (if (if (subtypep (typeof #:g0062) 'point) (let ((#:x0063 (slot #:g0062 'x)) (#:y0064 (slot #:g0062 'y))) (sys:setq x #:x0063) (sys:setq y #:y0064) (sys:setq #:result-0065 (prinl (+ x y))) t)) #:result-0065 ()))) data: 0: point 1: 1 2: 2 3: x 4: y syms: 0: struct-from-args 1: subtypep 2: typeof 3: slot 4: prinl 5: sys:b+ code: 0: 2003000E gcall t14 0 d0 d1 d2 1: 04000000 2: 04020401 3: 20010005 gcall t5 2 t14 4: 000E0002 5: 20020002 gcall t2 1 t5 d0 6: 00050001 7: 00000400 8: 38000016 if t2 22 9: 00000002 10: 2002000A gcall t10 3 t14 d3 11: 000E0003 12: 00000403 13: 20020009 gcall t9 3 t14 d4 14: 000E0003 15: 00000404 16: 20020006 gcall t6 5 t10 t9 17: 000A0005 18: 00000009 19: 2001000D gcall t13 4 t6 20: 00060004 21: 1000000D end t13 22: 10000000 end nil instruction count: 10 #<sys:vm-desc: 9966330> I see this is doing something silly: (subtypep (typeof x) y) is just (typep x y), but costs an extra gcall instruction. Either the pattern matcher should do this, or the compiler should have that as an algebraic reduction, or both. Let's do the compiler for fun: $ git diff stdlib diff --git a/stdlib/compiler.tl b/stdlib/compiler.tl index 58685741..a837571e 100644 --- a/stdlib/compiler.tl +++ b/stdlib/compiler.tl @@ -1411,6 +1411,8 @@ (defmeth compiler comp-fun-form (me oreg env form) (set form (rlcp ^(,bin ,a ,b) form))) ((- @a) (set form (rlcp ^(neg ,a) form))) + ((subtypep (typeof @a) @b) + (set form (rlcp ^(typep ,a ,b) form))) ((@(or ignore nilf) . @args) (if (eql sym 'ignore) (each ((a args)) Note that we are using pattern matching here to recognize and rewrite this case. In return we will obtain better code from pattern matching: $ make TXR stdlib/compiler.tl -> stdlib/compiler.tlo $ ./txr This is the TXR Lisp interactive listener of TXR 291. Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet. TXR is not a toy, but should be kept within easy reach of children. 1> (flow '(if-match @(struct point x @x y @y) (new (point 1 2)) (prinl (+ x y))) expand prinl compile-toplevel disassemble) (let ((#:g0024 (struct-from-args 'point 1 2))) (let* (#:result-0028 x y) (if (if (subtypep (typeof #:g0024) ;; this hasn't changed, of course 'point) (let ((#:x0026 (slot #:g0024 'x)) (#:y0027 (slot #:g0024 'y))) (sys:setq x #:x0026) (sys:setq y #:y0027) (sys:setq #:result-0028 (prinl (+ x y))) t)) #:result-0028 ()))) ** expr-1:1: warning: if-match: no such struct type: point ** expr-1:1: warning: new: point does not name a struct type data: 0: point 1: 1 2: 2 3: x 4: y syms: 0: struct-from-args 1: typep ;;; no mention of subtypep here any more! 2: slot 3: prinl 4: sys:b+ code: 0: 2003000E gcall t14 0 d0 d1 d2 1: 04000000 2: 04020401 3: 20020002 gcall t2 1 t14 d0 4: 000E0001 5: 00000400 6: 38000014 if t2 20 7: 00000002 8: 2002000A gcall t10 2 t14 d3 9: 000E0002 10: 00000403 11: 20020009 gcall t9 2 t14 d4 12: 000E0002 13: 00000404 14: 20020006 gcall t6 4 t10 t9 15: 000A0004 16: 00000009 17: 2001000D gcall t13 3 t6 18: 00060003 19: 1000000D end t13 20: 10000000 end nil instruction count: 9 ;; down by one #<sys:vm-desc: 92c94d0> Ship it!
- eastbound 3y agoOh yes, without the .stream()….collect(toList()) cruft! Just lists with .map() on them! Also without the :: operator, it’s uglier than the arrow equivalent and it’s yet-another-construct to parse.
- appplication 3y agoI disagree. One of the major critiques of Java is how verbose and full of boilerplate it is. And sure, you can hand wave that as devs being picky, but this is a real reason people avoid picking up new projects in Java. The verbosity serves no purpose, and less code is generally better. As for there now being multiple ways to write the same thing, this seems like something that could be easily linted into consistency. So you would really only have to learn the less verbose way for any newer Java projects.
- riku_iki 3y ago> of Java is how verbose and full of boilerplate it is. yes, new SimpleLang can have lessons learned during last 20 years implemented, as in example from another commenter: https://news.ycombinator.com/item?id=37068380 https://news.ycombinator.com/item?id=37068380 Currently, for a given task, Java usually have 5 legacy deprecated ways to solve, and two more in newish Java versions, and dev needs to keep all of them in memory to be able to read and understand other's code. > As for there now being multiple ways to write the same thing, this seems like something that could be easily linted into consistency. that's if you don't work with any legacy systems and 3p libraries and never switch projects/jobs
- user432678 3y agoSounds like Kotlin is exactly such SimpleLang.
- seanmcdirmid 3y agoYa, I'm not sure why people would use Java anymore given that the SimpleLang is pretty good.
- lmm 3y agoKotlin is even worse; it's younger than Java but also has 5 legacy ways to solve the problem and two more in the newer version, it's just that the legacy ways have been removed so any examples you find online won't work any more.
- earthboundkid 3y agoSomeone (I think pg?) said that patterns are just insufficient language features, but the flip side applies too: you can apply a pattern in any language, but a feature is limited to what the language designers provide. Patterns you can learn once and write anywhere (for better or worse).
- Jtsummers 3y agoPeter Norvig: http://norvig.com/design-patterns/ http://norvig.com/design-patterns/ (slide 4)
- earthboundkid 3y agoPN, so I was half right. :-P
- maxfurman 3y agoSounds like Kotlin to me
- riku_iki 3y agoin my non-expert opinion, kotlin also added bunch of creative, unobvious and opinionated constructs to not be qualified as "simple lang"
- cutler 3y agoTheir implementation of closures is ass-backwards. Just a bare pair of braces with no arrow to disambiguate from block parens. Kotlin also added to Java's verbosity with extra modifiers like 'internal', 'open' and 'by lazy' which isn't even grammatical English. And don't get me started on multiple constructors.
- pizza234 3y agoDestructuring (/pattern matching) itself is supported by several languages (although more in general, its flexibility depends on the language). It makes sense to support it in modern languages, as it's practical and intuitive. IMO it's a significant syntactical improvement, as it considerably reduces boilerplate assignments.
- riku_iki 3y ago> It makes sense to support it in modern languages the problem is that Java not modern language, but carrying all legacy features from last 20 years, so having all legacy features + new modern creative ideas make Java very complex.
- unlikelytomato 3y agoWhat are some examples of these legacy features? Overwhelmingly, I see complaints that java has been too simple compared to virtually all other languages. I agree that cognitive load is important. However, it feels really strange to me to suggest that java has reached the complexity of other similar languages. What am I missing?
- riku_iki 3y agofor example Java went through several generations of IO evolution, so some simple task like reading text file line by line can be done in many different way in current standard library: - using DataInputStream - using Scanner - using Reader - using Files.readLines and they all suck.
- unlikelytomato 3y agoI see. Is it fair to say that most of the issues area related to jdk included libraries vs language features itself? I also find a lot of the included libraries to be cumbersome, but I see these syntax improvements to be a welcome change in contrast.
- Blackthorn 3y agoWe're programmers. It's our job to know these things. There really aren't that many to learn. It's a much simpler task than various engineering fields.
- riku_iki 3y agothe job is to produce software and make this process reliable and efficient. > There really aren't that many to learn. I think there are a lot to learn in java ecosystem.
- yazaddaruvala 3y agoThe job is to communicate effectively while producing software more reliably and with less time than someone else that might get hired. There are many of us who think Java has very little to learn - asking us to go slower - while probably good for society in general, is a losing strategy in a Capitalist economy. You can keep up, or be left behind. Meanwhile, fortunately the “communicate effectively” is 100x more valuable as “produce software more reliably and faster” ie learning all of these new languages and language improvements.
- sbjs 3y agoThat was literally the point of Java, to be syntactically and semantically simple, in contrast to the extreme complexity of C++. But just like with Lisp, that only moves necessary complexity to another layer. True wisdom in language design is understanding the line between necessary and unnecessary complexity, and perfectly incorporating necessary complexity into the language so users don't have to reinvent the wheel at the library or precompiler level.
- kaba0 3y agoJava is quite a lean language, especially considering its age, and the design team does consider every new feature for a long time before adding, being an exception among languages with regards to feature churn (with all its negatives and positives). Just look at C# or C++, both have at least an order of magnitude larger language “surface area”.
- nxobject 3y agoBeyond the other posts, I wonder whether some of the reactions are due to the fact that destructuring here is purely syntactic sugar – there's no "fear of missing out" on new semantics that offer a drastic new improvement in programming style, to the extent that they feel obligatory to incorporate in your mental model of Java (e.g the introduction of anonymous functions.)
- trondeh80 3y agoKotlin is pretty close to this?
- riku_iki 3y agothis was discussed here in comment several times, and opposite opinion is that kotlin added enough creatives and opinionated constructs which make it more innovative and less simple. I think the closest thing is if someone would create linter for java which would allow only essential structures and library API. Java has very good foundational core.
- brap 3y agoThanks I hate it
- the_af 3y agoYou hate that it takes 2 lines instead of 4 (excluding curly braces) to accomplish the same? The new syntax is not even convoluted, it's pretty intuitive destructuring syntax already available in many modern languages.
- morepork 3y agoThere's potential confusion whether the int x from the example comes from point.x (field), point.x() (method) or point.getX() (common getter pattern), just one more gotcha
- the_af 3y agoBy reading the proposal [1], I see it's meant for record types. Records seem to be value classes, i.e. the equivalent to Scala's case classes. In that case, there's absolutely no ambiguity: there's only one `x` you can be talking about. By the way, value/case classes are such a boon. Very easy to get used to, and once you have, you want to use them everywhere, I guarantee. ---- [1] https://openjdk.org/jeps/440 https://openjdk.org/jeps/440
- morepork 3y agoThanks that makes more sense, I had assumed it was for all types as Point used in the example has the same name as a class in the standard library
- trealira 3y agoAnd that "older Java" example itself is an alternative (added in Java 16, from looking it up) to what existed before. if (obj instanceof Point) { Point p = (Point) obj; int x = p.x(); int y = p.y(); System.out.println(x + y); }
- monksy 3y agoScala obj match { case Point(x,y)=> println(x+y) }
- diarrhea 3y agoVery similar in Python and Rust as well.
- switchbak 3y agoSadly no one wants to talk about Scala any more.
- throwaway5959 3y agoEven for Spark?
- monksy 3y agoWe don't talk about spark
- throwaway5959 3y agoWhat? Why?
- klysm 3y agoPretty much the same as C#
- coding123 3y agoWhat is it saying here. Is the (int x, int y) from getters or the constructor? It LOOKs like a constructor, but I can't possibly imagine it's doing anything with the constructor in this call.... Which probably explains the person saying "I hate it".
- valenterry 3y agoNo, I think this only works on Java Records where it's clear what the identifiers are.
- kaba0 3y agoYou are destructuring the object here, and since it is a record type that is nothing more than its typed, ordered fields listed in the constructor, you just use it as its reverse function here, basically. Destructuring for other kind of objects are planned with user-defined destructors. But it does have plenty prior art, e.g. in haskell you can deconstruct lists arbitrarily like _:secondElem:rest would bind secondElem logically.
- morepork 3y agoIt's a bit of an unkind example as most would write the latter as if (obj instanceof Point p) { System.out.println(p.x()+p.y()); } But I can maybe see the value if you need to use x/y more than once. However in Java it's common to have getX() style accessors, for which this syntax doesn't seem that helpful as your variable would end up being called getX
- valenterry 3y agoI think this syntax for accessing x and y only works for java records anyways and not for methods.