7 ms·
"An accessible syntax that makes it less scary." Can anyone explain how syntax elements such as { } are a net win? This looks like they've tuned the syntax to
by Syzygies 5y ago
"An accessible syntax that makes it less scary."
Can anyone explain how syntax elements such as { } are a net win? This looks like they've tuned the syntax to not scare anyone off in the first week, at the expense of an economy of expression later.
Rob Pike once justified C syntax for its ability to survive pipes that mangled whitespace. That was then, this is now. To this old C programmer, anything that unnecessarily resembles C is ground glass in the eye.
- girishso 5y agoAfter years of Elm, the moment I see curly braces in a language I immediately lose the interest. Curlys, semicolons are not relevant these days.
- LangMakers 5y agoThey are only used in case-of and monadic blocks, and allow avoiding commas and semicolons everywhere else without having the annoying issues with meaningful spaces! I totally understand your initial impression, but consider reading my thoughts below before judging prematurely. (Guess I'll end up adding a bracket-less version of case-of to satisfy the hyper demanding crowd of HackerNews...)
- girishso 5y agoI read your comment elsewhere here defending the curlys and it does make sense, I was judging it prematurely. > Guess I'll end up adding a bracket-less version Don't make a decision just by listening to some random strangers like me!
- lincolnq 5y agoNooo don't compromise your vision for hacker news commenters! Great product design is a mix of flexibility and opinionatedness. You have to find your "users" and then build the thing they want. If HN commenters give you crap about it they're not your users, at least not yet, and that's ok. Your product doesn't have to appeal to everyone at the outset.
- platinumrad 5y agoWhy are people like this.
- lenkite 5y agoI guess you will hate both Rust and Go ?
- LangMakers 5y agoHmm. I understand your rejection for `{}`, but I really think the end result feels nothing like the Java experience. Can I have a shot at defending it? :) It will be a long answer including some of my reasonings, and by all means feel free to disagree if you think I'm wrong about something. Kind is extremely permissible and terse in general, and a lot of caution and love is put in making it very practical. While `{}` looks like noise in some places, it allows others to be less verbose, resulting in some snippets that look almost like Python, even though Kind isn't indentation aware (which, IMO, is very annoying). For example, commas and semicolons are always optional, so you can actually write lists as just `[1 2 3]`, maps as just `{"foo":1 "bar":2}` and function calls as just `f(1 2 3)`. That wouldn't work without `{}` on case. There are many places where the Haskell-like syntax break down. We aim to fix every one of these. For example, the following Haskell function: blocks :: Entity -> Bool -> Bool blocks entity floats True = True blocks entity floats False = case entity of Creature name hp age items pos -> True Tile pos effect isWater -> not isWater || floats Wall pos -> True Fire pos damage kind -> False Is equivalent to this Kind function: blocks(entity: Entity, floats: Bool, ghost: Bool): Bool case ghost { true: true false: case entity { creature: true tile: not(tile.is_water) || floats wall: true fire: false } } Both do the same thing. Which one is more readable? The key insight is that we avoid repetition of variable names (a consequence of Haskell's equational notation), and the need to re-name every field of every variant every time you pattern-match (by naming fields as `matched_name.field_name` by default). That sounds like a small thing, but pattern-matching is the bread and butter of functional programming. Having such a terse syntax for case-of makes the whole language feel so much more refreshing. Just like that, there are dozens of small little things that we do to make the syntax just work in practice. For example, working with Maybe is often frustrating in functional languages. In Kind, we have a default operator: let x = some(3) <> 5 // x is 3 let y = none <> 5 // x is 5 An "abort" operator, that flattens your code: sum_first_3(list: List<Nat>): Nat x = list[0] abort 0 // returns 0 if x is none y = list[1] abort 0 z = list[2] abort 0 x + y + z And, of course, Maybe monad: sum_first_3(list: List<Nat>): Nat Maybe { get x = list[0] get y = list[1] bet z = list[2] return x + y + z } <> 0 And the same attention we gave to Maybe, we gave to so many other small things. For another example, we HATE indentation. Pattern-matching a structure with only one constructor causes a needless indentation. In Kind, you can use "open", that flattens it too: open vec vec.x + vec.y + vec.z Another source of frustration in Haskell is setting/getting values from lists, maps, records. Things are so inconsistent. `Map.lookup`, `List.index`, `!!`. And lenses, while amazing, are currently really messy, hard to learn and read, full of dependencies and impact the performance. Kind has simple and obvious answers for all of these. For example: name = my_list[7] Works just as you expect, returning the 7th element of `my_list : List<A>` as a `Maybe<A>`. name = my_map{"foo"} Returns the "foo" entry of `my_map : Map<A>` as a `Maybe<A>`. And: name = my_record@foo Returns the `foo` field of `my_record` as `A`. Don't need a maybe? Just default it: name = my_list[7] <> "anonymous" Wanna set it? name = my_list[7] <- "Eric" That gives the user the convenience of working on JavaScript lists, in a pure functional language. Something else I noticed in Haskell is that code tends to become really messy when the function body becomes big. That is, when you need to chain many intermediate values. There isn't an obvious answer as to where stop growing horizontally and start adding lets vertically, and when to use `let` or `where`. Sometimes the computation flow becomes upside down, sometimes not. Also, foldr/foldl tends to become really messy when the function body is large. We have one straigth-forward answers to all these situations in Kind. Our let and "pure for" syntax allows for some pretty Python-looking functions: age_factorial(birth:_year Nat, names: List<String>): String // Concatenates all names in a string name = "" name = for name in names: name | " " | name // Computes the age age = current_year - birth_year // Computes the factorial of the age fact = 1 fact = for n from 0 to age: fact * n if age <? 18 then "You're too young to use this program" else "Hello, " | name | ", the factorial of your age is " | fact Obviously, pure fors just desugar to folds. Also, maps are well-thought. In JavaScript, `{foo: 3}` and `{"foo": 3}` both are the same map. In Kind, if you don't write `""`, then it is a variable, which makes a lot more sense. For example: key = "foo" map = {key: 3} Just a small thing though. This answer is already big, and it doesn't even cover things like the built-in HTML syntax, the `sigma` sugars (`[x: Nat] x <? 50` is the type of Nats that are smaller than `50`), other sugars for theorem proving, like `rewrite`... Basically, what I'm just saying that there are so many nice things behind the initial impression, perhaps you're judging prematurely because of your taste for `{}`? Give it a chance and I think you'll love it!
- munificent 5y ago> Rob Pike once justified C syntax for its ability to survive pipes that mangled whitespace. The C preprocessor would like to have a word with him.
- ketralnis 5y agowhich I'm sure Rob Pike is unfamiliar with
- captainmuon 5y agoI don't know, for me this doesn't look enough like C (or anything familiar). I would love a language like C# or Python where you could just put in preconditions using the expression syntax of the language, and it would try to prove it. If it can't prove it, it might ask for more facts, give a warning, or add a runtime assertion. As far as I know the only language that does this was the experimental Spec#. I would even go further and have complex preconditions as part of the types, so you could have say a Person with field "age" < 18 is of type Minor. (I know this is tricky. The objects would be immutable, or you'd only be able to specify Person|Minor and only narrow it with an assertion, for example). Nim has something a little bit in this direction with distinct types, and integer range types.
- touisteur 5y agoThat's exactly what Ada2012 and SPARK2014 did. You write your contracts (preconditions, postconditions, assertions, contract-cases, invariants, type predicates) in Ada syntax and you get both runtime assertions and proof depending on which tool you call (compiler or prover). You give more facts when proof fails. You can tag code as 'ghost' and it's only available for proof tools... To be able to be a bit more 'terse' in assertions, they added quantifiers, expression functions, case- and if-expressions. Lots of small improvements to allow contracts, that are finally a boon to write simpler and clearer code. Everything you're asking for here is available in Ada2012 and SPARK2014.
- nextaccountic 5y agoalso what https://github.com/facebookexperimental/MIRAI https://github.com/facebookexperimental/MIRAI does for rust: you add contracts (preconditions, postconditions, and invariants) using https://docs.rs/contracts/0.6.0/contracts/ https://docs.rs/contracts/0.6.0/contracts/ and it checks whether they are true here is an example using mirai and contracts: https://github.com/facebookexperimental/MIRAI/blob/master/examples/shopping_cart/src/main.rs https://github.com/facebookexperimental/MIRAI/blob/master/ex... (note: the contracts crate can be used for verifying at runtime as well)
- 5y ago
- lhorie 5y agoMy understanding (from reading arguments from language designers) is that curlies introduce error correction redundancy to a language. So if, for example, your editor decides to be stupid and mangle indentation of some copy-pasted snippet, the curlies provides the developer with semantic hints to deduce/reconstruct the original program. This property is particularly important for readability of "embeddable" languages ("embeddable" in the sense of a language source code existing within another, for example JS within HTML script tags, or bash in a Dockerfile, or YAML string concatenation).
- erichocean 5y agoI've recently started using TLA+, and the mathematical syntax was a big turnoff initially. Took two weeks before the entire approach "clicked", and now it's second nature and I like it a lot. If you need to think differently (as in TLA+), I think having a different syntax that reflects the different thinking is a good idea.
- hyperpallium2 5y agoWithout {}, it's insufficiently C-like http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html?m=1 http://james-iry.blogspot.com/2009/05/brief-incomplete-and-m...