7 ms·
OCaml Syntax Sucks (2016)
- the_clarence 2y agoWorked on an ocaml codebase for two years. My advice is: choose a different language. It's just not a great dev experience in general
- davesnx 2y agoCurious to know more, do you think can make a long-form of "why" and a detailed experience? If you have some time, would be massive to compare it with what's the same experience today
- eru 2y agoDepends on what you compare it with, I guess. (I worked in OCaml and Haskell and other 'weird' languages professionally in different jobs for many years.)
- akkad33 2y agoFsharp is pretty good in teams f tooling at least when compared to other functional languages
- nobleach 2y agoAlthough I'm not a Microsoft fan, their docs for F# are worlds ahead of anything I've seen for OCaml (I know a few OCaml folks are working to fix this). I've considered trying it for Advent of Code this year.
- neonsunset 2y agoPlease give it a try! And perhaps it catches your eye enough - it could use contributors too. (also: generally speaking the "core" of .NET is quite unlike most other products Microsoft puts out, so chances are you will be pleasantly surprised)
- akkad33 2y agoIt's definitely worth it to try
- otabdeveloper4 2y ago> Worked on an X language codebase for two years. My advice is: choose a different language. It's just not a great dev experience in general. I'm pretty sure it's "working on a codebase" that kills your soul, not the minutae of particular language choice.
- kamov 2y agoWhat were the main issues you came across? What language would you prefer if you had to start from scratch and had the choice to go with anything else?
- RandomThoughts3 2y agoI also worked on an ocaml codebase for a roughly similar time frame and found it extremely pleasant. Probably the best time I spent as a dev with working on an Ada project with a great architecture.
- shortrounddev2 2y agoI want to like OCaml, but the tooling isn't great and async operations require a library to work for some reason. I tried f# but if you want to do async operations there, you have to do them in these even weirder "computation blocks" with this annoying ! Syntax. I've found that the best way to write ML family programs is to let an imperative language handle IO and then write any more mathematically or logically complicated work in ML, but only after you've loaded all of your data
- neonsunset 2y agoSome F# articles are outdated - they predate F# 6 which added task { } CE which simplifies asynchronous code that interacts with .NET's standard library. I found F# to be more pleasant to work with async than C# (which is already a breeze). It is true that you still have to define 'task' (or 'async' if you want to use Async CEs) but it is generally there for a reason. I don't think it's too much noise: let printAfter (s: float<second>) = task { let time = TimeSpan.FromSeconds (float s) do! Task.Delay time printfn $"Hello from F# after {s} seconds" }
- shortrounddev2 2y agoI dislike that there's a kind of sub-syntax specifically for async. I like how C# converts `await` into the necessary calls. In this code I think it would look better to simply have: let async printAfter (s: float<second>) = let time = TimeSpan.FromSeconds (float s) await Task.Delay time printfn $"Hello from F# after {s} seconds" and then printAfter is called with `await` as well. I'm sure there's some FP kind of philosophy which prohibits this (code with potential side effects not being properly quarantined), but to me it just results in yet more purpose-specific syntax to have to learn for F#, which is already very heavy on the number of keywords and operators
- neonsunset 2y agoIt's the other way around. 'async'-annotated methods in C# enable 'await'ing on task-shaped types. It is bespoke and async-specific. There is nothing wrong with it but it's necessary to acknowledge this limitation. let!, and!, return!, etc. keywords in F# are generic - you can build your own state machines/coroutines with resumable code, you can author completely custom logic with CEs. I'm not sure what led you to believe the opposite. `await Task.Delay` in C# is `do! Task.Delay` in F#. `let! response = http.SendAsync` is for asynchronous calls that return a value rather than unit. In the same vein, seq is another CE that is more capable than iterator methods with yield return: let values = seq { // yield individual values for i in 1..10 -> i // yield a range, merged into the sequence yield! [11..20] // note the exclamation mark } Adding support for this in C# would require explicit compiler changes. CEs are generic and very powerful at building execution blocks with fine control over the behavior, DSLs and more. Reference: https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/computation-expressions https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...
- VeejayRampay 2y agoflamebait tantrum of a post
- wk_end 2y agoThe title is a little inflammatory. The critique is specifically about Ocaml’s handling of let-bindings. AFAICT OP thinks the syntax sucks because: 1. there’s no marker to indicate the end of let scopes 2. functions are bound with the same syntax as constants He asserts that this is confusing. In practice - for the many issues I have with Ocaml! - neither of these are actual issues, in my experience, once code formatting is applied. An actual serious problem with Ocaml’s syntax is that matches don’t have a terminator, leading people to mess up nested matches frequently. Pair that with the parser’s poor error reporting/recovery and things can become unpleasant quickly.
- nine_k 2y agoFortunately, the OCaml compiler is very modular, and there have been efforts to make things more... reasonable. - Reason, a different syntactic frontend for regular OCaml: https://reasonml.github.io/ https://reasonml.github.io/ - ReScript, a language with OCaml semantics that compiles into: JS https://rescript-lang.org/ https://rescript-lang.org/ (I suppose it's a reincarnation of js-of-ocaml).
- BrawnyBadger53 2y agoI feel like ReasonML should have the capacity to help bridge the gap for people learning ocaml if it weren't so hidden.
- Taikonerd 2y agoI wish they would update their blog![0] The last post is from Aug. 2018, which definitely gives the impression that the project is dead. But it's not dead, if you look at their GitHub.[1] [0] https://reasonml.github.io/blog/ https://reasonml.github.io/blog/ [1] https://github.com/reasonml/reason https://github.com/reasonml/reason
- davesnx 2y agoShame on me; I have a few draft posts that never got the chance to publish. My non-native english doesn't fully help ^^ Expect some of them to be published at the end of the year or early january!
- lemper 2y agoidk mate, his guide to pick prostitutes has more compelling argument compared to this article. i mean, almost all the time ocaml users don't write their stuff "nested".
- daelon 2y agoLink? I tried to look around the site, but I.. couldn't take very much of it.
- akkad33 2y agoThis one? http://xahlee.org/Periodic_dosage_dir/las_vegas/20031015_copulate.html http://xahlee.org/Periodic_dosage_dir/las_vegas/20031015_cop... Found it via Google
- acjohnson55 2y agoBig yikes.
- akkad33 2y agoF# syntax improves on this I think. But why is the article so short? It ends abruptly
- deleted 2y ago[deleted]
- laylomo2 2y agoThe more I used ocaml the more I found beauty in the syntax. It’s very ergonomic in many ways: 1. It’s whitespace insensitive, which means I can code something up really messy and the code formatted will automatically fix it up for me. 2. In general there aren’t a ton of punctuation characters that are very common, which is great for typing ergonomics. Don’t get me wrong, there are still a lot of symbols, but I feel compared to some languages such as Rust, they’re used a lot less. Beyond the syntax, there are a couple of things I really like about the language itself: 1. Due to the way the language is scoped, whenever you encounter a variable you don’t recognize, you simply have to search in the up direction to find its definition, unless it’s explicitly marked as “rec”. This is helpful if you’re browsing code without any IDE tooling, there’s less guessing involved in finding where things are defined. Downside: if the “open” keyword is used to put all of a module’s values in scope, you’re usually gonna have a bad time. 2. The core language is very simple; in general there are three kinds of things that matter: values, types, and modules. All values have a type, and all values and types are defined in modules. 3. It’s very easy to nest let bindings in order to help localize the scope of intermediate values. 4. It has a very fast compiler with separate compilation. The dev cycle is usually very tight (oftentimes practically instantaneous). 5. Most of the language encourages good practice through sane defaults, but accessing escape hatches to do “dirty” things is very easy to do. 6. The compiler has some restrictions which may seem arcane, such as the value restriction and weak type variables, but they are valuable in preventing you from shooting yourself in the foot, and they enable some other useful features of the language such as local mutation.
- bloomingkales 2y ago2. In general there aren’t a ton of punctuation characters that are very common, which is great for typing ergonomics. Don’t get me wrong, there are still a lot of symbols, but I feel compared to some languages such as Rust, they’re used a lot less. I never really seen someone put that into words. I always feel a certain kind of weird when I look at a language with tons of punctuation (Typescript is good example).
- akkad33 2y agoThe lambda syntax and default lambda parameters alone make typescript very hard to parse
- walterburns 2y ago[flagged]
- otabdeveloper4 2y agoThat's kinda his entire internet brand tho.
- KennyBlanken 2y agoAs a matter of policy can HN please not accept submissions with non-https URLs? It's a checkbox at most web hosts, built in to many reverse proxies, etc. There's no excuse for not offering htttps, particularly since it places users at risk if at any point along the path between them and you, there's someone untrustworthy.
- alurm 2y agohttps doesn't make content trust worthy.
- otabdeveloper4 2y ago> places users at risk Help me out here, what's the threat model here while reading troll programming blogs?
- yawaramin 2y agohttps://doesmysiteneedhttps.com/ https://doesmysiteneedhttps.com/
- otabdeveloper4 2y agoYou didn't answer my question. What is the threat model?
- perks_12 2y agoOne would argue that if you're that much at risk and still find time to click non-https-blog-posts the issue is in front of the screen, not in the connection
- anacrolix 2y agoI find it less abutting now that I know about let expressions in lambda calculus. it's still verbose though. do notation please.
- chombier 2y agoThere is a kind of "do notation" in OCaml with binding operators [1] (let*) for monads and (let+) for applicatives that is actually quite pleasant in practice. [1] https://ocaml.org/manual/5.2/bindingops.html https://ocaml.org/manual/5.2/bindingops.html
- asplake 2y ago(2016)
- cess11 2y agoMy OCaml is very rusty, but just add some parentheses, no?
- yawaramin 2y agoAnd set up the autoformatter to format on save. Redundant parentheses removed, et voila.
- user2342 2y agoWeak arguments in the article with badly chosen examples. If one wanted to criticize OCaml syntax, the need for .mli-files (with different syntax for function signatures) and the rather clunky module/signature syntax would be better candidates.
- _flux 2y agoI actually rather like the mli-files. It's a nice file to read, with the documentation and externally available symbols only. However, the fact that the syntax is so different is a bit annoying. Sometimes I wrote (haven't written OCaml for some time now..) functions like: let foo: int -> int = fun x -> .. just to make them more similar to the syntax val foo: int -> int in the module types.
- phplovesong 2y agoI actully like the mli files. Its a separate place to describe the PUBLIC API, and a good place for documentarion. Now you dont clutter your code with lots of long comments and docstrings.
- armchairhacker 2y agoThe problem with mli files and counter-argument to “they’re good documentation” is that, with a few visibility annotations (`pub let`, etc.) they could be auto-generated. Then you don’t have to write your entire public interface twice (sans the inferred `let` types, but I already prefer to make those explicit in the `ml` because otherwise you get much more verbose type errors when they don’t align with the `mli`).
- IshKebab 2y agoI 100% agree. The lack of clear scoping and function call grouping syntax just turns it into a word soup. It becomes difficult to parse for humans and I spend a stupid amount of time just getting the semicolons, begin/ends, etc. right. It's like... when you mismatch brackets or braces in a C-style language, except to resolve the problem you can't just find the bracket that's highlighted in red and count; you have to read an essay. I don't know why there are so many people here defending it. It's pretty clearly very elegant, but extremely inconvenient.
- edwintorok 2y agoThat can be indeed very confusing when you initially learn the language. However there are 3 things that can help: * An auto-formatter (ocamlformat integration in your editor, or ocaml-top) that shows how the actual nesting looks like * You can add ;; at the end of a top-level function to get a syntax error at a better location * Use the LSP integration of your editor which will show you where the error is as you type, so you catch the problem early
- IshKebab 2y ago> Use the LSP integration of your editor which will show you where the error is as you type, so you catch the problem early Yeah I do have this set up and it's a very good LSP, but unfortunately frequently if you get the nesting wrong the error is like "the entire rest of the file is wrong". It's often not very helpful. That's not unique to OCaml. C style syntaxes can give "everything after this point is an error" if you get brackets wrong, but it's much easier to figure out what you did wrong.
- dgan 2y agoUse ocamlformat and set "profile = janestreet"
- pxeger1 2y agoI believe OCaml's syntax does suck, but I don’t think this article gives a compelling argument as to why. Missing an `in` turns a let expression into a top level binding and kicks a syntax error often a long way down the file, making it very hard to identify the cause. The relative precedence of let, if, match, fun, and the semicolon is unintuitive and hard to remember, making me want to add loads of unnecessary and ugly parentheses. On the other hand, I like that there's little overloaded syntax, and the meaning of different characters is fairly consistent.
- boccaff 2y agoIf anything, OCaml's error messages are something that sucks, especially for newcomers. The `Error: Syntax Error` message that points to an empty last line in the file leaves you doing the parser work, in a language that you don't understand.
- bvrmn 2y agoIt's a strange take that a possibility to write unformatted code means syntax sucks. I've read other articles and there is other weird stuff. Like Java has perfect syntax because on one line you could do so less. In the mean time modern "functional" (or "monadic") style java is a chained mess with ridiculously long lines.
- jatins 2y ago> In the mean time modern "functional" (or "monadic") style java is a chained mess with ridiculously long lines. I have seen many devs that prefer the Java imperative style over more functional chained style. Could be an outcome of leetcode style interviews or that most CS programs start with C/python/Java style languages but it's not uncommon to see that preference especially among junior devs
- bvrmn 2y agoThe funny thing real functional languages doesn't use dotted chains. It's quite a stretch to try to make something functional without adequate syntax support. Java streams really make things a more difficult than it should be.
- frankie_t 2y agoI've recently started a mini-project in OCaml, having some Haskell background. The worst thing so far is that you have to declare and define functions before using them. This results in unimportant utility functions being at the top, and the most important functions being at the bottom of a file. I haven't had much issue with let bindings, however that might be because my functions are fairly simple for now.
- gsuuon 2y agoThis is generally a pro for me. I can skip to the bottom of a file and see what the main purpose of it is, knowing that it's the only place that could reference everything else in the file.
- greener_grass 2y agoI've always liked this - it follows the structure of a good academic essay
- bmitc 2y agoYep. Datatypes, helper functions, and then the good stuff. In every file. It is actually beautiful and easy.
- RandomThoughts3 2y ago> The worst thing so far is that you have to declare and define functions before using them. That's an extremely good thing. Unordered definitions and where are some of Haskell worst decisions with lazy by default, overuse of operators and a community which sadly think point-free is desirable. That's the kind of choices which makes Ocaml a lot more readable.
- frankie_t 2y agoI guess it's a matter of taste, for me reading the generics and big picture first is more important than the details. Maybe it's my programming skills, but my files start with some five or ten string manipulation utilities and helpers. I honestly do not even care about their implementation, a name would suffice. Which is why I also like `where` approach much more than `let ... in`: it allows you to read the general idea, postponing the details to later (if you want to go into them). However, I agree on laziness, operators and point-free.
- 4ad 2y agoOther commenters have already expressed their opinion about the shallowness and inadequatenessof the article, so I will touch on a different, more technical point. The author doesn't understand why OCaml (and Haskell, and many HM-derived languages) have let ... in ... at all, as opposed to having, say, just lambdas. That's because of a feature of Hindley–Milner type systems called let-polymorphism[1]. This is hard to see in OCaml if you are not intimately accustomed with HM type systems because definitions always use let, but in Haskell it's immediately clear that something more interesting is happening because regular definitions do not use let. F#, which has been heavily inspired[2] by OCaml got rid of the in, rather it uses indentation to do automatic in insertion[2]. OCaml does not want to be indentation-aware. [1] https://en.wikipedia.org/wiki/Hindley–Milner_type_system#Let-polymorphism_2 https://en.wikipedia.org/wiki/Hindley–Milner_type_system#Let... [2] https://fsharp.org/history/hopl-final/hopl-fsharp.pdf https://fsharp.org/history/hopl-final/hopl-fsharp.pdf
- Koshkin 2y agoThere’s indeed something wrong with a syntax that needs double semicolons all over the place.
- cccbbbaaa 2y agoIt doesn't. They are useful for the REPL only, to tell it that a statement is over. I prefer this over what Python does, which is to consider that an empty line is the end of a statement. Copy-pasting functions from a file to the REPL can be a bit tedious because of this. In OCaml, all I have to do is to add ;;<enter>, and I'm good to go.
- SkiFire13 2y agoAnother thing I personally hate about OCaml's syntax is the order of generic parameters being backwards. I know why it's like that, but it still doesn't make any sense to me both as a programmer and as a non-native english speaker.
- nsonha 2y agoI'm not even an ocaml dev and I prefer how it reads and types to that of C family generics.
- SkiFire13 2y agoWould you mind expanding on why do you prefer it? I'm not too focused on e.g. not using angle brackets, which is pretty common in the C family (though funnily enough they are not used in C), but rather on the order with type arguments being before the generic type, for example the type of lists of integers being `int list` rather than `list int`.
- nsonha 2y agoMy mother toungue has the reverse order to English grammar too, but I've spoken English long enough for that to not matter. If we're talking about, say, consistency with function syntax, then to me a function is a verb, and a type is a noun, hence still consistent. I mentioned the typing experience because I hate to have to 1. open and close braces 2. press shift while typing [2] is also the reason I prefer generics in python and scala than that of java and C#
- ubertaco 2y agoIt's definitely quirky in its inconsistency, but type 'a Tree = | Node of ('a Tree, 'a Tree) | Leaf of 'a Is saying "The possible cases for the type describing an 'a Tree are: a Node of two other 'a subtrees, or else a Leaf of an 'a." Then when you concrete-ize it, you have an "int Tree" or a "string Tree". This is a little clearer with thinking of the List datatype: this is a number list, that's a string list, that's a grocery list, this is a guest list...etc. One nice thing in F# is that there's an ability to "standardize" how you write generics to look more like the (admittedly arbitrary) way that C# or Java or C++ write them: type Tree<'a> = | Node of (Tree<'a>, Tree<'a>) | Leaf of 'a
- misja111 2y agoI tried out OCaml last year for solving the AOC puzzles. I managed to solve all of them in earlier years using Haskell or Scala, but this was the first time I gave up. It was not as much the syntax, it was the schism between the OCaml standard libraries and those from Jane Street that turned me off. Whatever I was searching for on the Internet, resulted in a mix of links to either of those libraries. It was confusing and very frustrating.
- nobleach 2y agoI get that. Having read Real World OCaml back when it was an O'Reilly book, I had a hard time not thinking Core was the defacto OCaml std lib. And its horrible documentation made me think the OCaml community was dead - or at least brain-dead. It appealed to one type of learner: Someone who just needs to see type signatures and has no interest in examples of how it could be used. After reading OCaml From The Very Beginning my stance softened. Learning PURE OCaml is a must. (if you want to do AoC with it). You may find yourself bringing in Core or Base, after you've got a good idea of a solution. It's definitely a fun language for doing AoC... but it can become extraordinarily frustrating when you hit a wall and all the StackOverflow answers assume Core.
- yawaramin 2y agoYup the thing that people recommending Jane Street libraries to newcomers don't realize is that they are made by and for a well-established team of OCaml developers who have been extensively trained in how to use it in Jane Street. Outside of the warm protective bubble of Jane Street's tribal knowledge, it's a more difficult task to pick up and understand their libraries with their often minimalistic documentation.
- hajile 2y agoI much prefer StandardML's syntax as it's far more consistent and doesn't have all the weirdness.
- ubertaco 2y agoThis is such a weird complaint that it feels like engagement bait. "Let x be equal to 4 in x * x" is a natural way to express a concept in English. The equivalent OCaml code is: let x = 4 in x * x I'm not sure how that qualifies as "sucks"? In fact, the `in` makes OCaml's scoping rules some of the easiest to follow. This is valid OCaml code: let x = 4 in let y = 3 in let z = 2 in x * y * z let x = 5 in let y = 6 in let z = 7 in x * y * z The phrasing of "let x = 4 in <this expression>" makes it explicit where x is defined as 4, vs where it's instead (in a different expression) defined as 5. I have an easier time understanding scope in OCaml, which explicitly spells out its scoping rules in plain-English syntax, than I do in Rust or JavaScript, which use the deceptively-simple-looking braces but also wild concepts like lifetimes or hoisting.
- yawaramin 2y agoAnd for people who don't like writing so many 'in's, we also have 'and': let x = 1 and y = 2 and z = 3 in x * y * z Which indicates that the binding of y can't refer to x and so on.
- steinuil 2y agoI've written a lot of OCaml and I always thought `let .. and .. in` indicated that the definitions were mutually recursive and that you could refer to y in x, like in `let rec .. and` or `type .. and`! That's surprising.
- yawaramin 2y agoI never thought about it much before but after seeing let+ and and+ 'debut' as operators for applicative functors (ie parallel application) it sort of clicked for me then.