Why did you learn OCaml?

If you’re interested in further information about the relationship between functors and type classes, there are some blog posts about it.

2 Likes

This is exactly how I feel, captured perfectly.

2 Likes

I think that succinctly states why this doesn’t look like a very useful substitute. A system that has to carry this functionality around as explicit baggage isn’t really adding much. When I’ve needed it, it has been simpler to use something like a struct of partially applied functions, or a “first class” module - essentially, a jury rigged OOP solution.

I should add, to branch back slightly towards the general subject of Haskell virtues, it has, built in, something like a ppx(?) extension that I see mentioned frequently, the deriving operation that can automatically derive a type class instance for many common cases. For example taking the very useful “Show” class – variants, records etc. types can simply be followed by deriving Show, and that’s done.

1 Like

Interestingly, this is exactly why I think it is a more useful substitute. When you’re out of the library and into the main executable, you always want it to be obvious what the types are going to be at runtime. Give me one example of something a type class can do that a module can’t that doesn’t amount to simply using a qualified name. It does result in a sort of inversion of the style—you might end up using functors of functors of functors—but it’s not going to result in requiring any more function definitions than a type-class-based solution. It really is only about typing extra qualifiers in client code.

deriving is glorious, and is a definite advantage in Haskell, especially deriving Show. In OCaml, we have [@@deriving sexp], but this is ppx and requires JaneStreet stuff, which you mentioned earlier was a problem for you because Haiku OS. It is regrettable that getting opam working on your operating system is a challenge—thought it is not one faced by most OCaml users. ppx is built into OCaml, but nothing specifically like deriving or Show, which is too bad. If one is in the unusual scenario that opam is unavailable, one would need to roll their own ppx for this.

3 Likes

Functors allow you conveniently to write implementations conforming to an interface (the relevant module signature). That’s as close as you are going to get to type classes in ocaml. Whether you like it or not is probably mainly a matter of familiarity. Furthemore ocaml does not support ad hoc polymorphism, aka function overloading, except via pattern matching on variants: having written an implementation of a module interface you have to specify the particular implementation you want to have effect in a particular case (say, via ‘let open module-name in’). The compiler will not do it for you, although as I understand it modular implicits may allow this in the future.

Some think that the absence of ad hoc polymorphism is an advantage and some don’t. ocaml for example has a polymorphic equality operator. Many experienced ocaml programmers avoid it.

4 Likes

Yes, that’s one way to put it. It isn’t the end of the world, but “mainly a matter of familiarity” is not quite right. Haskell makes massive use of typeclasses in its library (Show, Read, Num) in ways that make for more productive programming, and that same functionality is there for you to use in your own code.

1 Like

allow me to introduce you to the Map.Make functor.

But seriously, OCaml modules are structurally typed. I didn’t have to add Int or Float to the “typeclass” until I needed it ad-hoc at the call-site. Float and Int (for example) implicitly define many of the same interfaces that mean they can be “functorized” effectively.

3 Likes

Two thoughts: (1) lots of systems-programmers find ad hoc polymorphism to be much, much, much more trouble than it’s worth. IIRC the Google C++ Style guide pretty much forbids it. And why? Because it means that somebody who comes to your code, has to learn an entirely new language – the language you defined using your overloadings – in order to understand your code. It was and remains a real problem in C++. I remember back in the mid-90s, Bard Bloom once noted that basically every C++ “framework library” (and there were a lot back then) created its own language, via the overloadings of various basic operators that were an integral part of the functioning of the library. One of the big changes with the C++ STL is that almost nobody needs to do overloadings, and as I noted, it’s frowned-upon by the biggest C++ shop in the biz.

(2) As for polymorphic equality, is that really ad-hoc polymorphism? I’d argue it’s just structural equality over runtime values, and as a systems-jock, to me that’s something more -primitive- and -prior- to any type system. It’s a good example of where Ocaml shows its roots as a systems-programming language. B/c back when a megabyte of memory was a lot, everybody programmed with an eye to the underlying machine, even when programming caml.

2 Likes

And not to be too snarky, but at my current level of intoxication, I feel the need to point out the irony of this phrase coming from a user of Haiku OS who can’t install opam. :zipper_mouth_face:

(I’m just messing with you. As a full-time Linux user, I do experience a microcosm of the pain you must feel in Haiku OS with regard to software unavailability)

2 Likes

C++ is a difficult one. It has emerged as a bolting together of different ideas of what is a whizzo language feature rather than being designed, and so lacks any of the consistency of languages like ocaml. I actually don’t mind function overloading so much: it’s rather more function templates which seem to me to tend to behave in arbitrary ways by being universally typed, only recently tamed in C++ by a type class look-alike in the form of ‘concepts’. The interaction between templates and overloading is itself problematic. Given a function definition template <class T> T square(T), is the addition of an int square(int) type an overload or a specialisation? It’s an overload, whereas template <> int square(int) is a specialisation. The first could have a different return type, the second couldn’t. The second can have SFINAE apply to it, the first can’t. What a mess.

I actually wouldn’t particularly mind the equivalent to function overloading in ocaml, but we have pattern matching which covers much of the same ground, albeit pattern matching of variants requires some runtime work.

The polymorphic equality operator is not an example of what I would call ad hoc polymorphism, it is universally polymorphic. My point was rather more that either form of polymorphism entails the compiler deciding what implementation to adopt in a particular case. While undoubtedly being convenient, it has its downsides.

1 Like

But functors do not. Just a thought.

2 Likes

For nearly 20 years, I was an AIX user. For some of those years, I had AIX laptops, and was solely an AIX user. No open-source software was properly-written for AIX: it all needed hacking to get it to work. [Specifically, the way AIX did shared-libs was … “special”.] B/c AIX was … “different”. Not for any good reason, of course. But not like I’m gonna change that. So I got used to “porting” software to AIX. And I’d carry along my big-ass tarball of ported packages, from machine-to-machine, along with a script to build and install it all, so I could get real work done.

It’s just part of what we must do, when we use oddball operating systems. I wouldn’t expect the maintainers of various open-source packages to maintain support for AIX – how could they get access to AIX machines to do so? Why would they want to learn the quirks of this operating system that almost nobody wants to use?

If I’m going to use an oddball operating system that nobody else uses, I think it’s incumbent on me to do the work.

4 Likes

I know what you mean. We have AIX (for Tivoli) and Solaris (for the library catalog system) at work. I don’t work on them directly, but our systems programmers also end up having to find their own solutions for things that would be trivial on other systems. Specifically, I know the Solaris programmers can only write in C or Perl. :scream:

1 Like

“We have AIX (for Tivoli)”: You have my condolences (for Tivoli).

[not some SUN fanboi here, but …] Wait, wut? Back in the day (meaning: 2007-10] Solaris was, like, the “unofficial reference standard” for OSS. Everything just built there, no problemo. Really, it’s gotten worse, eh? That’s … hilarious in a way.

AIX though: man, that shit, what an abomination. They started off with BSD and -broke- it. As a colleague said to me in week 1, back in March 1995: “if we didn’t break it, we couldn’t call it our own”. Crikey. I remember around 2007, IBM had a bunch of OSS packages they’d compiled for AIX, that were made available for download. The GZIP RPM was corrupted – somehow, the zip code was wrong and didn’t correctly zip (or unzip – I forget which). Insane.

2 Likes

For me as an end user, Tivoli is actually pretty cool, but I don’t know what the admins have to go through…

Re: Solaris. These days Solaris is dead (Oracle doesn’t work on it anymore. There is only Illumos now, but it’s not in the market position Solaris ever was). I don’t know the exact technical situation for the catalog software, but I get the impression that it’s a very locked-down Solaris kind of thing. It could be that the OS is vendored by the people who sell the catalog software. I’ve never bothered to find out the details, as I (thankfully) don’t have to work on that stuff.

please, no.

1 Like

For me, AIX didn’t look like any broken BSD, it was SysV with Berkeley sockets. Yuck. I think it was only around 15 years for me.

Anyway, it seems rather unfair to

  • comment about Haskell typeclasses, that OCaml doesn’t support ad hoc polymorphism, and then say
  • who needs ad hoc polymorphism anyway, look at how awful C++ overloaded functions are

Haskell typeclass is ad hoc polymorphism, but it’s far from that example of overloaded functions. Maybe ad hoc polymorphism, good/bad per se isn’t a very illuminating way to think about it.

2 Likes

I think you have missed the point. That was not what I (at any rate) was saying. If you like Haskell type classes (or C++ concepts, Rust traits, C# and Java interfaces) then use them. Ocaml has functors and module signatures to cover similar micro-surfaces. Most people on this discourse group seem to use a multitude of languages. Being a purist probably won’t work as well.

2 Likes

[replied directly about AIX, doubt anybody here cares grin]

I don’t mean to comment directly about Haskell’s typeclasses. Rather, abut operator overloading in general. As I noted, it’s been a bane in C++, and justifiably banned/deprecated by big shops that have good reasons to care about code comprehensibility.

2 Likes

OK, but even taking that restricted case - just operators - it’s possible to draw the wrong conclusions from the dreadfulness of C++, which is the type of operator overloading that would likely be banned.

I wouldn’t care to take on an analysis of the soundness of C++ operator overloading, vs. say the Haskell typeclass system which can do something very similar, but even in the unlikely case they’re about equivalent there … to the C++ programmer, “+” is an intrinsic arithmetic operator that comes with certain casting rules, and that’s the first level of how it relates to the actual types. To the Haskell programmer, it’s a function in the Num class, thus naturally overloaded for all instances of Num, so whatever it’s doing must go back to the Num instance for the strictly determined type. Whole different deal.

So … when they come to OCaml and see + for int and +. for float, both of them are going to think it’s kind of sad, but the C++ programmer from a type system with implicit casts and operator overloading, the Haskell programmer from a system with type classes, and the two have no real relation to one another.

2 Likes

But nobody’s saying C++ is dreadful. Hell, I sure ain’t gonna say that. It’s actually great, and is one of my three go-to languages (C++, Ocaml, Perl). Google is a massive C++ shop. The reason they forbid overloading isn’t so they can work around something “dreadful” in C++: it’s because operator overloading means that you read a piece of code, and have no idea what it does, until you figure out what all the operators are overloaded-to. And that, that gets in the way of software quality.

1 Like