7 ms·
Isn't that Clojure? (let [p obj] (if (instance? Point p) (let [x (.x p) y (.y p)] (println (+ x y))))
by nkh 3y ago
Isn'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!