6 ms·
Having never tried OCaml, what advantages does it have over other languages? Two languages I don't know seem more interesting, Clojure and Rust. Generally I wor
by coldcode 10y ago
Having never tried OCaml, what advantages does it have over other languages? Two languages I don't know seem more interesting, Clojure and Rust. Generally I work in Swift these days.
- the_af 10y agoOver other languages in general? That's hard to say about any language :) OCaml is a language in the ML family, is backed by INRIA and is the main language of Jane Street Capital (so it definitely has "real world" use!), which also contribute a lot to it. OCaml is pretty good for functional programming, and unlike Clojure, it's statically typed. If you like static typing -- which I personally think is the way to go -- that's a huge reason to prefer it over Clojure. You may also check out Haskell if you go that way. An interesting case study about going to OCaml from another language (Python, in this case) was posted to HN many times already: http://roscidus.com/blog/blog/2014/06/06/python-to-ocaml-retrospective/ http://roscidus.com/blog/blog/2014/06/06/python-to-ocaml-ret.... I recommend you read it if you want to learn more about why would one choose this language. Why not choose a language in the ML family? Well, if not having C-like syntax is a deal breaker for you, then OCaml is going to frustrate you. A real programmer shouldn't let syntax stop them from learning new languages, though :) Ultimately one has to try doing something with this kind of language, even if it's just a toy project. Just reading about it won't enlighten you much, and you will end up focusing on its syntax instead and deciding it looks too unfamiliar.
- owl57 10y ago> Well, if not having C-like syntax is a deal breaker for you, then OCaml is going to frustrate you. There is a new alternative Reason syntax (https://facebook.github.io/reason/mlCompared.html https://facebook.github.io/reason/mlCompared.html) which replaces some of the unusual syntax with braces and semicolons. Though it still probably looks less C-like than Swift. And I haven't tried writing anything in it, so can't say for sure if it really feels less weird than standard syntax on a "real program".
- int_19h 10y agoIMO, the single most interesting thing about OCaml is its object model. On one hand, you have a fairly conventional setup with classes, methods, inheritance, generics etc. On the other hand, the entire system is structurally typed, with pervasive type inference. Recycling bits from my earlier comment on the subject... # let f obj x y = (obj#m x)#n y;; val f : < m : 'a -> < n : 'b -> 'c; .. >; .. > -> 'a -> 'b -> 'c = <fun> Here I defined a function taking 3 arguments, called method m on obj, passing x as argument, then called method n on the result of that, passing y as argument. Note the inferred type signature for this: the first argument is of type <m : 'a -> <n : 'b -> 'c; ..>; ..> - i.e. any object that has a method named m (and possibly some other unspecified members - that's what ".." means), with said method m having a signature that allows us to pass some 'a, and returning another object of type <n : 'b -> 'c; ..> - i.e. something with a method named n that accepts 'b and returns 'c. 'a and 'b' are then used as types of x and y, respectively, and 'c is the the result of f.
- nv-vn 10y agoI would say that the most interesting feature (for me) is the module system (although with structural typing as a close second) :)
- groovy2shoes 10y agoThis is actually row polymorphism rather than structural subtyping. The difference is rather small, but important: Under structural subtyping (or any kind of subtyping, for that matter), the subtyping relation admits a rule called "subsumption", which can lead to information loss. Consider this behavior, under structural subtyping: fun f {x : real, y : real} = {x = 2 * x, y = 2 * y}; (* f : {x : real, y : real} -> {x : real, y : real} *) f {x = 2.0, y = 3.0, z = 4.0}; (* it = {x = 4.0, y = 6.0}; *) Above, when `f` is applied to a subrecord with an additional `z : real` field, the result is missing the extra field! This is because the subrecord was subsumed by the (super-) record type taken by `f`, leading to information loss. This is the reason why you often see people using up-casts in languages like Java (especially before generics were introduced) and Go (which is lacking generics for some befuddling reason): up-casts allow you to circumvent the type system and force a particular value to take a particular type, thus recovering the lost information, but can be unsafe. Under row polymorphism, however, you can achieve basically the same effect, but you get to save any unused/irrelevant type information inside of a row variable (the `..` in your example) and include it in the result. Then, no information is lost, and no safety is compromised: fun f {x : real, y : real, R} = {x = 2 * x, y = 2 * y, R}; (* f : {x : real, y : real, _ : ..a} -> {x : real, y : real, _ : ..a} *) f {x = 2.0, y = 3.0, z = 4.0}; (* it = {x = 4.0, y = 6.0, z = 4.0}; *) Users of languages like Lua or Python might be reminded of "duck typing", and not without reason: row polymorphism enables many of the same programming patterns/techniques/abstractions in typed languages that are enabled by duck "typing" in untyped ones. It's a shame that more typed languages don't incorporate the idea, because it's a really wonderful one, and it can lighten the relative "burden" of writing typed code in some cases :) The folks at INRIA has come up with some really neat stuff, and, if you haven't already, it's definitely worth it to check out their publications, too!
- int_19h 10y agoOh, and the other neat thing is that OCaml cleanly separates subtyping and inheritance. In other words, in OCaml, class inheritance is for implementation reuse only, and is completely orthogonal to subtyping. In many common cases (similar to Java etc) inheritance does produce a subtyping relationship in practice; but because of this decoupling, you don't get one shoehorned onto your classes when you just want the other.
- PeCaN 10y agoHonestly for me, it's just that it's damn useful. It's not especially new and shiny and hip, but it's easy to think in and easy to reason about. OCaml is a nice tool for writing software. That's about it. It's pretty simple functional programming that can switch to imperative and object-oriented programming where appropriate.
- patrec 10y agoOcaml is concise yet comparatively simple (despite various warts), offers good javascript interop and (quickly!) compiles to fast code and has a good type system. It's extensively used for language prototyping and tooling (e.g. at facebook). Rust's compiler was originally written in Ocaml: https://github.com/rust-lang/rust/tree/ef75860a0a72f79f97216f8aaa5b388d98da6480/src/boot https://github.com/rust-lang/rust/tree/ef75860a0a72f79f97216.... Compared to Rust it compiles much faster, offers an interactive shell and is more expressive and mature, but doesn't offer similar low-level and parallelism capabilities and eco-system coherence (e.g. there are half a dozen competing build systems). I also believe that Rust, with it's clearly defined niche will win a much bigger total market share. Compared to Clojure it offers static typing, much better startup times and native code compilation, but doesn't have similarly modern functional datatypes and the standard library is less well thought out. There are a couple of other things which are rare or nonexistent in other languages: - Polymorphic variants, the article linked downthread has some use cases - extensible variants - Functors (see https://realworldocaml.org/v1/en/html/functors.html https://realworldocaml.org/v1/en/html/functors.html) - a structurally typed OO system, as someone has already mentioned It also has a few interesting syntactic ideas that I wish more languages would steal: - Nice sugar for passing keyword arguments: `f ~somearg` is the same as `f ~some_arg: some_arg`. I wish I could do `f(=somearg, y)` instead of `f(somearg=somearg, y)` in python - It supports new user-defined operators in a way that doesn't render your code unreadable, because the precedence is derived from existing operators. - A nice syntax for "importing" from a namespace for an expression. Assuming Mod defines `foo` and you can write Mod.(foo x (bar f x)) instead of `Mod.foo x (Mod.bar f x)`