Blog and Conversation of FP/OCaml/Elixir/Scala

Wrote some general considerations about functional programming nowadays. It’s not Elixir specifiс, though Elixir is mentioned, as well as this forum :slight_smile:

https://medium.com/@lakret/some-controversial-and-not-so-much-opinions-about-functional-programming-e515d5edbc7

8 Likes

@lakret

But do people writing Erlang err more often than those who use OCaml?

Absolutely yes. As a programmer of ocaml and erlang for well over a decade, and of elixir for multiple years, I absolutely make a LOT fewer errors in OCaml than I do in erlang/elixir. Heck, I just left a lot of errors in a module just yesterday that I know are going to crash spectacularily because I was asked to for the moment, and unlike OCaml where I can just toss in a failwith "TODO THIS" and have it compile and typecheck and I get a very nice easily greppable thing that I can search for, in Elixir I instead can just leave it empty (and pray that I remember to put in a # TODO: blah or so) and maybe hit it in production later.

I absolutely make fewer errors in OCaml, like substantially so, like it’s not even a comparison of how many fewer I make, and it’s because of a lot of reasons, a big few (definitely not inclusive) are:

  • OCaml forces me to handle every case, rather than just failing to run-time errors if it happens to be tested for (else yay production-splosion)
  • The Type system catches SO MANY little mis-types and accidents and stuff that leak in to Erlang/Elixir to eventually crash later.
  • The Type system let’s me even encode some logic in to it so it can even catch a lot of logic bugs that just silently go through in Erlang/Elixir.
  • The tooling of OCaml is superior to Erlang/Elixir, both in terms of IDE plugins and features, code coverage tools like this (and a lot lot more):
  • SIGNIFICANTLY faster compiling, like ohmygod kind of faster! Like Elixir is a dynamic language and so it ‘should’ be faster, and OCaml is a full native optimizing compiler of the realm of languages like C, and it still blows Erlang/Elixir away in their compilation speed (which still makes me think that Erlang/Elixir’s compilers could be significantly improved). Really, don’t underestimate the amount of productivity enhancement you get from a fast compilation process. (EDIT: Just for note, one big reason that OCaml compiles so fast was that the language was designed to compile fast, where things like elixir are not.)
  • And still so so much more…

But when I see things like:

But do people writing Erlang err more often than those who use OCaml? My experience tells me that this is not the case; I believe that a lot of supposed “error prevention” of static functional programming languages is due to immutability and side-effects separation, not due to static type systems.

That honestly seems to tell me that the person has not done substantially sized project in both styles yet.

8 Likes

But the problem with this statement:

That honestly seems to tell me that the person has not done substantially sized project in both styles yet.

is that I did :slight_smile: Not with OCaml, but with F# I wrote quite a lot of code back in the day. I also was doing mostly Scala for the last 5 years or so. Mostly analytics applications, both for the largest Russian IT company and for my own clients (started doing consulting work 3 years ago). Funny enough, one of my main points in the post is this:

And those “you just don’t understand Haskell good enough” arguments?

Do you see my point now? :smile:

I do understand the sentiment that you express, and I do agree that initially, when you first start your app, you may have fewer errors with OCaml than with Elixir. But the thing about type errors: they are the easiest to catch. So you start it, with OCaml - it does work, with Elixir it fails, you go, change that one line, and now it works. You write tests in both, you find bugs with those tests in both, and most of them are not related to types really. But you just don’t have all those horrible corruption of state errors in either system. And debugging Elixir and figuring out what’s goining on in the live system is much easier than any statically typed functional language that is in a wide use today.

I just migrated sizeable API with lots of business logic from Scala to Elixir. Elixir code is almost 2 times shorter; I actually found and eliminated some logical errors that I had in Scala code. And this was my first project with Elixir, and god I lost the count which project with Scala. The LOC (calcualted with clock) for Elixir project is 17k lines; 28 tables in the db with non-trivial schema; 150 controllers; rabbitmq integration, websockets, etc.

Also, keep in mind, though I write in dynamic language, I can add those dializer specs and most of it will type check without much problem. Statically typed languages do structure your thinking in a good way, but once you have that, you just don’t need that anymore as much.

The problem that I wanted to highlight is that it’s really not about any particular language or type system. Look, you’ve been pretty much triggered :smile: by my rather innocuous comment. And I fully understand you, 4 years ago my reaction would’ve been pretty much the same. And then I started using Elixir, and OMG, it turns out Universe does not collapse onto itself when you don’t have ML-style type system :smile:

Another point: I do like OCaml a lot. I’m kinda disappointed that Facebook puts so much effort into Reason, instead of promoting superior language… But anyways, OCaml being viable option for the frontend - that’s just beyond amazing. I actually plan to play with your TEA library later this week :smile:

And one last thing about tooling: c’mon. Does OCaml have observer? Tracing/debugging in running systems? Mix (OPAM is … not very good IMHO)? Even sane and easy to use project structure where you can specify all the deps? Excellent inline docs support? I do think that tooling became much better than it was 3 years ago, definetly. But some things, like type inference and error reporting in the IDE I care about; coverage - not so much.

9 Likes

Actually I find the type testing less useful at the beginning, I find it the most useful later on in later development and in maintenance steps. By that point I no long have in my mind the code I’m working on, it may as well be someone elses code at that point, adding new features comes relatively easy as the compiler then tells me all the places I need to touch instead of hoping that I wrote enough tests (potentially tests that don’t exist yet if new code).

And this is a big thing, the type tests ‘are’ testing, but built into the language, unlike elixir where you need to not only test the logic, but you need to test the types as well and to make sure they are in the proper form, which is a LOT of extra code over, say, the equivalent OCaml.

That is entirely an aspect of the BEAM VM, not the language. Alpaca (a statically typed language on the BEAM VM) is just as debuggable as Elixir.

(On an aside, there are many thing people keep conflating to be a feature of a language that is not, it is rather a feature of it’s runtime, independent of the language, or various other things.)

Not surprising, I find Scala dreadfully irritating to read and it is substantially longer than equivalent OCaml or Elixir code (where equivalent OCaml tends to be shorter than Elixir, though I rarely directly type something unless I’m disambiguating or refining something).

/me worked with scala for a couple of years about 5 years ago

No, it won’t. Dialyzer is a Positive Typer, not a Hindley-Milner typer. They are entirely different typing systems and positive typers assume that the human author is correct when faced with situations that it cannot figure out, where an HM typer demands unambiguity. Consequently Dialyzer catches very few of the actual errors I hit.

At least until you need to start doing things like maintenance on the code after you’ve slept a few times since last touching it. ^.^;

Except I’ve worked with both for near 2 decades at this point (~17 years for erlang and ocaml, ~3 for Elixir, and professionally with erlang/ocaml for about 4 years and professionally with elixir for about 2), at my current job right now I professionally work with a very large Elixir project, OCaml code, and with smatterings of Erlang (and javascript and such). The OCaml code I cannot think of when I’ve ever actually needed to debug, it’s one of those things where if it compiles then it works, compare to Elixir where for every line I write I spend debugging (not necessarily on that line, but usually interactions elsewhere) at least 5 times the amount of time. Dialyzer helps a little but it is amazing just how much it misses. I’ve tried faking typing systems and tagging tuples and far far more but short of ‘enhancing’ every dependency I deal with it is always an incomplete move.

Observer is a back-end thing. Elixir does not have Observer either, it is the BEAM VM that has observer. After all, do you keep observer if you use the Elixir->Javascript converter (Elixirscript)? No. That is a tool of the platform, not of the language.

Again, a tool of the platform, not the language. When OCaml compiles to the BEAM then it will have all those features as well.

OPAM I find quite fantastic. It is significantly more powerful than Hex (comparing OPAM and Mix is… well, wut? OPAM is like Hex, you should compare Mix to ocamlbuild). I can even have different compiler versions, custom configurations, all kind of things the likes of which that Hex could never hope for in its current design (though it would be fantastic to add).

How what I think you mean to do is compare Mix to ocamlbuild, and yes ocamlbuild is a load of crap, it is also ancient, and yes it is even being replaced. The next OCaml major version has a new build system called Dune, which is based on JBuilder, which is a replacement of ocamlbuild made by Jane Street years ago, which many project do indeed use instead of ocamlbuild. But yes, ocamlbuild is pretty bad, but JBuilder/Dune are quite fantastic and are about on par to Mix in capabilities (has some extras in some area, Mix has extras in other areas).

(EDIT: For note, OPAM is more similar to a combination of ASDF + Hex plus some other handlings)

Uh, even the old ocamlbuild has dependency management (though JBuilder/Dune does it even better). o.O

Oh god yes! OCaml’s doc comments ((* ... *) are normal comments, (** ... *) are doc comments) are wonderful! There’s a built in full ocamldoc system (a bit ugly default template but it works really well, and you can re-theme it of course), and it’s all been in there for far far longer than Elixir has existed (in one form or another it’s been available for 2+ decades). You can even do a form of doc tests via a PPX as well if you wish (or via caml4p (included in OCaml) in OCaml versions pre version 4).

Yeah OPAM popping up a few-odd years back was a huge boon, everything supports it now. It’s awesome. :slight_smile:

It was just an example (of many many examples) of things that can be added to OCaml (and already are) as plugins. It specifically shows you every-single-branch that is taken or not via your tests. :slight_smile:

13 Likes

I do know that those (observer, debugger, etc.) are features of Erlang VM. I did work with Erlang some time ago, my first full-time job after uni. Worked there for 2 years, highload, financial info, 4 people on the team, lots of features, no problems with maintenance. But it was painful because of the Erlang quirks, it was before Hex, so you can imagine. Elixir just blown my mind by comparison, though I hope that Erlang story is now also better, since you can use Hex.

Sorry, yep, I meant ocamlbuild … partially. The problem is - I don’t need to care in Elixir about those 10 or so tools that OCaml has, all of which are supposedly amazing, but have terrible docs, and you actually need to search for them. In Elixir I can just type mix help and voila, I can see everything. The workflow is just better out of the box. And this is important, esp. if you start with the language: how many people do you think gave up on OCaml because it has terrible docs, and those tools are scattered all over the place? I can use mix as task runner, to test, compile, publish, document my code, to run migrations etc. Maybe not very UNIX-y, but extremely easy and seamless to use.

From your description it seems that it’s weird that you use Elixir at all :smile: Yet you do, so it must have something that OCaml doesn’t right? :smile: And this is not something small: we’re talking actors, Phoenix, much larger number of high quality libraries, etc.

The problem is: people from statical typed languages often obsess very much about the language. But many people just don’t care about that this much! Language is a large part of the story, but all the infrastructure around it, naimly learning resources, libraries, tooling, IDE support, etc - that matters at least as much as language itself.

Scala is way popular than OCaml, though it does have awful type system, there’s so much inconsistency, and… I did more Scala than any other language, yet I just never get this feeling of my code being nice. I started playing with OCaml a month ago, after 4 year break from any ML language, and I still remember the language rather well, and everything I write is so nice. But this little property of being able to use it in Java projects and reuse all of the existing packages just made it so you can use it for actual work, and with OCaml… maybe, if you have unlimited time to reinvent the wheel, and your employer is ok with that. Never was that lucky though :frowning:

When OCaml compiles to the BEAM then it will have all those features as well.

Oh, that’s something I would’ve been more than excited about!

But again. The post is not about OCaml hate. Scala-hate - maybe :smile: The post is about assumptions that people make about each other, arrogance of some people in the community, and dismissal of actual real world situation. You do have problems with dynamic types; I don’t. Does it make me worse than you at what I do? Better than you? I don’t think that’s either is the case. It’s just different people have different preference; our brains work differently; we never see the actual state of the affairs, just our perception of it. My view is as imperfect as yours; just in different ways :smile:.

And yeah, I don’t like Scala-the-language anymore, but I’ve been working half time for the last couple of years, and I was fast enough to never be a blocker for a team of 7 people for whom I provide pretty much all DB and most of the query logic of analytical system that tries to compete with BA tools like Looker and Zoomdata. And yeah, the next thing I’ll build, I hope to build in Elixir :smile: Yet, a lot of people who’ll read my Scala comments will infer that I’m not successful using the language, pretty sure about that.

5 Likes

Hmm, I’m curious what those were? I actually found erlang fairly straight-forward and sensible. :slight_smile:

Well, other than things like rebar(1) being brand new at the time, and just cloning libraries that you need… But C++ was the same way at the time so it was all natural to me… ^.^;

(/me might not settle for that anymore though…)

Well all that I mentioned other than the code coverage tool are all built in to the main OCaml setup and their documentation is fantastic (though the code coverage tool showed has excellent documentation too). Documentation definitely was an issue even as recent as 5 years ago, but I’d not say that anymore as everything I can think of uses ocamldoc (built with OCaml itself) straight now (which can output quite a variety of formats).

Though. to be honest, that VERY much does not follow argument parsing standards… ^.^;

The ocaml programs, on the other hand, ‘do’ follow argument parsing standards (like the help for ocaml is just ocaml -h/ocaml -help/ocaml --help) in addition to the manual pages (man ocaml). All of which work on elixir as well (always better to follow standard methods). :slight_smile:

Certainly not where I work, it has been taught at this college. ^.^

Uh, not really? All I do is install opam (via whatever method, usually _ apt install opam for me), init it for my user (sets up environment and all so I don’t have to do it manually) via opam init, then choose whatever ocaml version I want to work with (latest ‘release’ is usual, so just run opam switch 4.05.0, or see a list with opam switch list, or if you want to see every-possible-variation-in-every-possible-way then run opam switch list --all, and of course you can do opam help or opam help switch to insta-open the correct man pages, or use the usual commands), then I have everything from ocaml to the optimizer to the documentation tool to the tester to more and more and more, at which point all you really need to know is just ocamlfind to see everything you have and how to use them (ocamlfind help to insta-open to the man page, or the standard arguments as well). Which is not any more steps (rather it is less) then installing the BEAM VM via erlang, then installing elixir, hoping you have the right versions because neither lets you switch versions or compilation options (unless you want to install ‘yet another’ tool like asdf for that), then you have to know all the different commands like escript/elixir/iex/mix at the least (and there are others too that you use less often), so you finally figure out that mix is really the main entrance point and you try mix new and when adding dependencies you notice that hex can’t always get everything for you so you occasionally have to do things like install rebar via another mix command and so forth, and that’s not even getting into the horrors and side-cases of releases! It can go both ways you know. :wink:

Still, all of these are far FAR better than what almost every language dealt with in the past (like oh-god-making-releases-in-erlang-15-years-ago-was-PAINFUL).

Three big reasons, the BEAM VM (which is why I used erlang), Macro’s (elixir specific thing), and the tooling for it on the BEAM VM (Elixir has the best BEAM VM tooling of any BEAM VM language thus far).

The BEAM VM. Honestly if I ever get around to actually writing an OCaml back-end for the BEAM VM I really will likely just use it from then on out, but that is a non-trivial task and I’m busy… ^.^;

Yep, the BEAM VM. :slight_smile:

I’ve used cowboy extensively in the past (which is what phoenix is built on), and mochiweb before that, and yaws before that. Phoenix is a nice set of helpers on cowboy, and it has a great channels implementation, it saves me work, but it is not the only choice on the BEAM. :slight_smile:

Hmm, I’m curious how the erlang vs elixir library count is at this point, Elixir definitely grew faster than erlang ever did, I’m quite curious, hmm…

Definitely don’t care about the language, but I do care a lot about what the compiler can do for me to save me work (both now and in the future). And if the BEAM VM gets a good statically typed language that is of sufficient overall quality I’ll switch to it easily (I always end up on the BEAM with everything eventually… ^.^), but right now the best overall language for features is Elixir. Do know that I find the dynamic typing a detriment, it is something that is overcome by the other features, but assuming all else equal I WILL choose a better typing system than a simple positive typer due to how much it helps, and it really does take a lot to overcome the advantage of static typing, but the BEAM VM really has a lot, I mean a whole lot, which is what helps for the work that I’m doing.

Do note, I pick OCaml over, say, Python or perl or so in almost every case when I’m making little programs to do ‘things’, but that is a far cry from the always running server world that the BEAM VM enables.

Lol, entirely agree. It was very capable, like very capable, but it feels… ‘unclean’ to me in a similar way that Haskell does…

OCaml can really easily interact with C/C++ libraries (it’s FFI system is quite nice, and even if you want finer control making a C/C++ shim is very easy and first-class supported in the build systems), and if something can easily interact with native libraries then it can interact with anything. This is why you see most OCaml libraries do more unique things, usually things to make programming easier, as there is little point replicating libraries that you can already link to. Similar with js_of_ocaml/bucklescript, they are designed to re-use the javascript ecosystems.

Yeah making a BEAM VM backend for OCaml is entirely one of my play-plans if I ever get time for it, but again, it is not a small undertaking (though the OCaml compiler has such fantastic integration points, easier to make new backends for it then about any other language, but it is still extensive). :slight_smile:

Lol. I actually quite like Scala. It has some major warts, but when I have to work on the JVM I really prefer working in it then anything else I’ve come across. ^.^;

Yeah, easily 95%+ of all of my bugs I encounter just become impossible to even occur in a language like OCaml or other similar ones. The rest are simple logic and design bugs that can hit anything, but those 95% I deal with in Elixir take up quite a substantial amount of my time…

It’s entirely possible, I’m very much from a typed world, from the ol’ days of pascal and C (weakly typed, but still typed) to C++ and template meta-programming (whoo making strong typing systems!) and more, I’ve very much not been in the dynamic typing world and every time I reach in to it, it nibbles back, a lot, a thousand paper cuts slowly shredding my time in ways that I would not experience in other languages… I’m just a human and like all human’s I am a horrible data analyzer and I want the computer to do as much work for me, instead of me, as possible, and dynamic languages force me to keep so much more in my head (thinking how the types weave through the multitude of function calls to make sure I don’t screw some invariant up 20 calls away) than I prefer to do otherwise, I’m getting old anymore… >.>

The BEAM VM is near magical, for what is was designed to do it has no equal. :slight_smile:

That also says to me they’ve not use Scala enough. I honestly think from experience that every programmer can list not only a multitude of amazing parts but also a multitude of cons about the languages they like best, and if they can’t list both pros and cons (of really every language) then they really have not used it enough. Even here in Elixir, it has a lot of amazing parts that really are truly Elixir (The Language) and not part of the BEAM VM, I may not harp on those as much around here as I do some cons but that is really just because I get drowned out so much since these forums are geared toward Elixir, but the language really has a lot of fantastic aspects about it, ignoring the lack of decent typing. :wink:

/me wants to split this thread into another thread, but can’t figure out how to link to the original blog post posting and putting that in a new thread while also keeping the original here, may have to make it ugly and manually link to it instead…

7 Likes

Yep, rebar and libraries (or lack thereof) were main offenders. I liked the semantics of language a lot, let it crash, actors - that’s something that became a true love in development for me. Some problems were also due to the main person working on the project not being very experienced with FP at the time, but he wrote a lot of core code, we pretty much had our own web framework built. He was an OOP guy, so a lot of not needed indirection and stuff. I see those problems now rather clearly, but back than I was just not experienced enough myself :slight_smile:

Oh, that’s something that I definetly missed. My issues are a lot from aesthetic perspective, and in some sections there are not a lot of examples, stuff like that. I didn’t really revisit it much, since for some weird reason I still remember most of the language pretty well. Guess it’s a good property to have in a language :smile:

I agree, but at the same time, I suspect that a lot of people coming from the Rails world, e.g., don’t really care. I personally would’ve preferred it to be mix --help and mix -h.

Oh, thanks. That’s the thing I completely forgot about! :slight_smile:

That’s something that I always wanted to build as well. The problem is - I don’t know the internals of VM that good, and somewhat rusty. I’m going through the elixir sources, though. Hopefully, somebody will do it someday. Maybe even you or me :slight_smile:

I liked the integrated experience. The reason why I started looking for porting our backend to something other than Scala was mainly a desire to use Postgres instead of Mongo. Scala simply lacks anything even close to Ecto in terms of completness of support of some Postgres features that we needed + proper migrations, schemas, changeset, etc. I was on a micro-framework train for a long time, but here I just needed to do pretty standard REST API with websockets + I needed to port it in 2 months, otherwise I think my client would’ve just said to me to stop :slight_smile: Phoenix helped a lot, and now 2 other guys from another team started contributing to this service, which is amazing.

Another important thing is all this umbrella apps support and the fact that you’re not really that much locked in to Phoenix. I like to keep my options open :slight_smile:

This is a phenomenon I myself try to understand. Erlang was obviously great even 5 years ago, but it seems Elixir’s decision to go with Ruby-like syntax paid off tremendously. And macros, yeah. I think they simplify library work a lot, you can provide easier to use interfaces, thus more people want to use your library, thus you have even more desire to build something else using it.

I did it with F# for a long time, but recently I started doing this with Elixir, and suprisingly it’s rather good at it. But I rarely need to do any math-related stuff, mostly orchestration, deployment, compress this, rename that, download from here, that kind of stuff. If I needed to do something like small analytics tool, I’d probably go with Julia nowadays. I wish OCaml had better libraries for this kind of stuff.

Hm, that’s something that I never considered. FFI is in many languages problematic. I had a lot of fun doing it with ports from Erlang back in the day, we had a significant portion of Python scripts that were executed by Erlang, just because Python back in the day had better tools for scraping websites (we needed to scrape a lot of data from government registries available only through webpages). I’ll look into OCaml’s FFI, thanks.

I have love-hate relationships with it :slight_smile: I’d prefer Clojure as my language, just for the sake of consistency, but startup times make it unusable, sadly. Or anything with ML type system/syntax. But Scala is a default choice for a lot of things for me still. Just not the language I’d use in my free time for fun.

I think that’s just preference. You don’t like dynamic types, maybe that’s why your brain struggles with dynamic languages? And yeah, I understand the sentiment fully, all this FP journey for me started from being just mesmerized by Haskell’s type system and all this power to express your domain so clearly and succintly. I started seriously looking into dynamic typed languages because of Elixir, and it turned out that I really tried to put square peg into round hole all the previous times I tried to use them. Very much like when people start doing FP and their head almost explodes when they try to understand folds :smile: But then it becomes second nature. Now I can easily switch “typing paradigm” in my head, and go from writing Elixir to writing Scala without much headache.

Fully agree! I think a lot of my language hopping is because of it. I fall in love with something, but then I start using it, and after a couple of years I just feel like: “Maybe this new thingy will solve some of my pains?”. But the new thingy just has another set of problems :smile:

Also not sure how to split it …

4 Likes

Hehe, ouch… ^.^;

I actually learned OOP in C++, I did not ‘unlearn’ OOP by learning FP for example (I already knew and used FP style ‘with’ OOP), rather I unlearn’ed OOP by once hitting the Thousand Paper Cuts Problem of OOP head on, which thankfully I was able to figure out due to doing a lot of assembly work and knowing how CPU’s worked, and a rewrite ran wonderfully. I was much younger then… ^.^;

I don’t care much for or against aesthetic perspective, and the few times I do I usually just apply a custom CSS to a website. ^.^;

Occasionally I PR my changes to the relevant projects (like the factorio mod website ^.^).

Actually both mix --help and mix -h work fine. :wink:

Lol, I often live by ocamlfind, it can easily give me paths to all my different switches without needing to switch between them so I can bake in specific version tests. ^.^

Up until recently I would have compiled to either Elixir or Erlang, but recent BEAM VM changes have made handling other languages directly on the BEAM VM SO much nicer (especially in regards to debugging and docs!). :slight_smile:

The BEAM VM’s bytecode is not… perfectly documented, but it’s very simple and easily deduceable via outputting the bytecode as text or reading the C source. :slight_smile:

Heh, up until Ecto I usually just wrote straight SQL… >.>
I still have to do that on occasion with Ecto due to Ecto limitations, but those are slowly being resolved (like multi-prefix joins! Whoo!).

Before my current job I would have just used either cowboy directly or done it in C++ depending on what needed to be done. Plug is quite nice though, I like the design, it’s simple and basically a big pipeline. :slight_smile:

I’ve never liked umbrella’s, even back in erlang days, never understood them. I instead make each application a dependency of just a single glue application that otherwise does nothing but link them up together. I find it much easier to test and integrate this way.

Yeah this really is a thing of syntax I’d imagine. Erlang’s syntax is simple, powerful, concise, but it is not the style that most people learn nowadays (you can even get elixir’y macro’s in erlang…).

Heh, yeah OCaml expects you to bind to C libraries when the C libraries already exist, and they do, but most people of most languages look for libraries in the language they are using, instead of looking for ‘native libraries’ in general, it is a bit of a shift to make. Even in C/C++ I’d still check for C/C++ libraries before I’d check for, say, fortran libraries, so it is a hard habit to break. :slight_smile:

Look at how Rust does it too, Rust has a fantastic FFI system as well. :slight_smile:

I try to learn at least 3 languages ‘fairly well’ each year (sometimesoften more, rarely less), and I occasionally add new ones to my usages. Most recently was Rust. Before that I guess you could say Elixir, but I consider Elixir as just a newer skin on top of Erlang so it doesn’t really seem or feel new to me, before that at least was probably Scala ~6 years ago (It finally made the JVM bearable!). Before that the one I’ve “kept” was probably Erlang a good ten+ years before that (with occasional dabbling in Python, but Python never ‘stuck’ to me, I know it well, I’ve used it in non-trivial things quite a number of times, but it is not one that feels ‘comfortable’). OCaml was about the same time period as erlang. Before that, like a good more ten years earlier was probably C++, before that was C, before that was Delphi and Pascal (getting into my single-digit years now, fortran didn’t really click for me until later, and I don’t really use it anymore, though I don’t use delphi/pascal anymore either), and before that was assembly (I so LOVED assembly on the old motorola and PIC chips!). ^.^

But yeah, I have a set of languages I use depending on the problem I’m solving, sometimes I mix and match too, but my main bulk in no real order (as they are situation dependent) are: C++, Erlang/Elixir, OCaml, Scala/Kotlin (because JVM things forcing me), and, hmm, javascript I guess since I have to use it on the web too often…

3 Likes

I came from being design patterns guy who actually liked C# to the guy who tries to avoid OOP even in languages where it’s bearable. Rich Hickey’s “Simple Made Easy” caused a shift in my head :smile:

I remember it being quite understandable. Though devil in the details, as usual.

I thought about trying to add another frontend to Elixir itself, because I don’t care about OCaml’s standard library that much (everybody uses Core anyways), syntax and types are big pluses for me. But this may render the effort useless, since it may cause a lot of problems with debugging for people. Either way, this is a hefty undertaking…

I pretty much ended up doing this with Slick. And Slick is a good example of types going wrong, I think. Database is already strongly typed, so it would’ve been nice to reuse this, have some kind of integration with your schema. Type providers in F# are quite cool as an idea, but never worked properly in practice.

There’s thing that I often dream about. It’s gradual typing on steroids. Not Dializer-style (success types), but rather something TypeScript/Flow style, where some parts of the system are fully type-checked, but you can write dynamic without any problems in other. Just imagine being able to write some parts of OCaml code with it. Those few places where types are not a good fit.

In a current system that I develop there’s a part that’s written in Scala, the most complex things in it are parsers for several query languages and some SQL / network calls specs generators for those queries. This is something that I wouldn’t be comfortable doing in a dynamic language. If the system were written in Elixir, I’d just use ports to connect with OCaml-generated binaries or something.

At the same time, this API layer and DB things are fine in Elixir, I honestly think that it’s better fit. Due to Ecto and Postgres, you already validate input and output, so it’s kind of a gradual type system in itself :smile:

But this design has a disadvantage - you need to communicate with Akka cluster from OTP, I ended up just bringing RabbitMQ in the picture. It would’ve been so much cooler, if you could have both properties of dynamic and static with minimal friction in one language.

I’ve been tortured by Prolog in the university, so I never had a problem with Erlang syntax. I prefere Elixir, but wouldn’t sweat too much about writing in plain Erlang either :smile:

Never mastered C++ enough. I alread knew Delphi, and it just felt like going backwards. And then Haskell-adventure happened, so never revisted it. But Rust stuff is beyond exciting, I never thought that I can have that much fun doing low-level stuff. I ended up writing some small scripts in it also, mostly data generation for testing (several TB datasets), it was delightful.

And yeah, rust’s FFI is understandable even to me, which was surprising!

I started programming from Turbo Pascal :slight_smile: Still hold rather dear memories of it, but probably would’ve been horrified if actually needed to use it nowadays :smile: The lowest-level I’ve ever got was adding some assembly code to speed up animations in Pascal.

I think for me the languages of choice are currently in this order: Elixir, OCaml, Rust, Scala, Python (never was my main language, but always a useful thing to have in your toolbox), JS (with ES6 it became somewhat tolerable for me). So, it seems I’m truely type-system agnostic :smile: I played with Go for some time a couple years back, but it just too verbose and not that powerful featurewise for me, Rust seems to be clearly superior. I started looking into Julia recently, and it seems to actually have some kind of interesting mix of typed and untyped, but pretty early in my learning still, so don’t have a complete picture yet.

4 Likes

It doesn’t have a ton of corner cases thankfully, it’s pretty forward. :slight_smile:

+1

I wish bucklescript baked it in, instead they are deciding to invent their own new standard lib, for what reasons I have no clue… >.<

Thankfully js_of_ocaml works with any of them.

Actually the new sections on the BEAM chunks fixes that quite well, you can even debug into your language from another if you want. :slight_smile:

Yeah they are a workaround for the lack of first class modules and functors that OCaml has as well as PPX support, all of which F# lacks.

Not too hard to do actually, you just need some kind of black box type that you can match out of, and such a type is absolutely necessary on the BEAM VM I still state, at the very least for things like messages, process dictionary, etc… etc… etc…

If it’s binary parsing then nothing really beats Erlang’s/Elixir’s binary parsing (of which OCaml has a PPX that duplicates it). For text based processing, well, there’s tons and tons and tons of things out there (including for Elixir and OCaml). ^.^;

If you want to get tortured a bit more, install erlog (prolog on erlang). ^.^

C++ was essentially my life for 20 years. I have no doubt I was one of top 100 of the foremost template meta-programmers in the world for a while there, not that that’s a good thing, but I could do magic. ^.^;

It was quite nice, especially it’s IDE’s blew away about all else at the time, but yeah, it died shortly after learning C++.

Hehe, I took to Rust fast, it’s borrowing system was almost identical to the types and styles I was already using in C++ so it was awesome to see it backed into the language and checked by the compiler for me (whoo!). :slight_smile:

Lol, I have that, probably still have my old install 5" floppies around somewhere too! ^.^

Yeah, it is just so used with so much stuff that you are losing much by not knowing it.

Agree, ES6+ helped a lot.

I exceptionally hate Go. It may be typed but it does it in about the worst way that I could possibly imagine. In addition the ‘standard’ and about all libraries are moving to this whole context pattern (think an Elixir Pipe, but bad…) and in such way that it introduces that whole ColorFunction issue of Javascript all over again in a new, unique, and horrifying way (yes I know it uses Go as an example of it not having these color functions, but I think Go didn’t have that context stuff back then…). Plus, what on earth about no generic/templating functions?! You have to have overrides for, say, each integer size! o.O!

Yeah I’ve barely looked in to Julia. I see a lot of the scientific-world of python stuck in to it, but I found some things I really did not like about it’s design (of which I’d choose python still) and as I had no work that needed it’s kind of features I have not looked in to it more. >.>

3 Likes

The whole F# story is a story of missed opportunities, sadly. Microsoft not making it a default choice, so few people really believed in it from the start, but all the design choices Don Syme needed to make to accomodate to .Net. I think it may’ve been a tremendous success if it targeted JVM instead. BTW, F# does have a rather nice macros system, but it never became popular in the community for some reason. Not PPX level, though. I’m quite sad that the language is in decline, but hopeful that OCaml will fill its place soon :smile: If some of F# features, like light syntax or units of measures made it in the OCaml I’d also be glad (though there are PPXs for both, I believe). Active patterns are also cool, but I never really needed them much.

Yep, something similar exists in C#, dynamic, but since C# has excellent reflection, people tend to use it instead. Also, there were some limitations if memory serves, and since CLI is static, there’s no need to use it in most cases.

In Scala, Akka’s (in)famous Any => Unit thing kinda makes a trick in one place, but I’d like to have refinrment over it, something like a flow / typescript spec.

Yeah, parsing is not a problem in most functional languages. But the internal language is complex enough, so at some point I went with phases approach, like in most compilers. I like how static type system helps you to delimit those cases, but sadly there’s some boilerplate as a result as well. In theory it can be helped with something like extensible records or HLists, but Scala implementations of both are not very good in my view.

Wow, it seems we soon have Smalltalk or Forth ported to BEAM as well :smile:

This was quite shoking for me as well. When the manual pretty much tells you to “just copy” or “drop types with dynamic interface” for the smallest possible changes of the types in input parameters. And it has awful effect on the codebase size => awful effect on the test amount required => it becomes very hard to modify even for smallish apps.

4 Likes

Yeah I’ve heard that in many areas.

Like losing the 2 biggest things from OCaml, the Module System and everything that comes with it, and PPX’s (later when caml4p was replaced by PPX’s anyway), massive things that make OCaml what it is as a language. F# has the type system, but it has to make a lot of accommodations to fit .NET calls and the lack of the Module system and PPX’s.

Really? You think that is because of the JVM itself or rather the communities around each?

Also really? What was it capable of? Was it possible to create a transpiler in it to transpile F# to another language like how you can do with PPX’s in OCaml? (PPX’s can go ‘both ways’ in essence, like Elixir Macro’s.)

Heh, not at all hard to replicate with first class functor modules though (different syntax of course, but just as safe).

Those just yell at me that they copied Scala’s Matchers. ^.^;

But again, it’s a bit of sugar over basic things, and yep there are PPX’s.

I’m curious what you’d have in mind?

Yeah this is in my opinion one of the only times that OCaml’s Row-Records, more commonly known as Objects, are useful, it is quite unique in how OCaml distinguishes between static records and row-typed records, usually a language either has one or the other, not both.

Uh… I may have a mostly-done implementation of Forth (with macro’s!) I’ve made on Elixir? ^.^;

And this right here is horrifying to see in a language doc yeah! o.o

I.E. “Or use C-style void* pointers!!!”

/me twitches

2 Likes

Yes, I agree :smiley: One the other hand it is extremely productive to get something out. I ported part of our main product to go (and erlang and java and halfway through (rust and ocaml)). Obviously I know the domain, and I am quite a capable erlang programmer so obviously erlang was fast to implement.

But, getting it done in golang was almost as fast. The standard library is fantastic (for my needs; I know people complain a lot about it but I take it, it must be web-folks complaining that higher level libraries are not there). Things like crypto, ASN.1 parsing, sql interfaces, options parsers, even basic HTTP server and client (which works surprisingly well). I don’t think I’ve seen any language with this out-of-the box capabilities.

In terms of lines of code, even though verbose, it is still pretty good.

I can write go-code pretty fast, BUT do I feel confident in the code? Hell no! :smiley:

I almost get the same type of errors I get when I write python. I get more run-time type errors than when I write erlang.

And because it is a very mutable language you get all sort of weird bugs.

I think golang mostly attracts:

  • People from python/ruby or other dynamically typed non-functional language
  • C people

Both of who feel the type system is a step up compared to what they are used to.

Rust is actually pretty good. It was heaps to learn in the beginning but then it was OK to write in. The problem though, here I have to rely on 3rd party, one-man-band libraries to do the core things I want to do. They are semi-implemented. Often just wrappers around an inconsistent C API. Not at all fun to work with. Documentation is OK

OCaml is the same. The core language is great, but mature (dare I say enterprise?) libraries are just not there. Documentation is sparse. You can look at what the types are but that doesn’t help you knowing if a function raises an exception :confused: and then you don’t try for it and application crashes and you don’t have beam to help you. (perhaps the compiler can warn of unhandled exceptions?

If you want to make a language popular, make sure you have the same “just write and go” experience as go and you have come a long way. Elixir is actually pretty good here.

I also believe immutability and side-effect free code is more important than static typing (i.e proper static typing a la ocaml/haskell)

I’d love a static type system on the Beam but I don’t see it happening (i.e getting the traction of erlang/elixir) and it it happens it is years away from being production ready…

Do I get more errors writing erlang than the little ocaml I’ve done?

In the small, yes. I.e the ocaml compiler finds the problem before I run the tests. The erlang compiler doesn’t find it until I’ve run the tests or started it.

But this is during development. Do I actually have many type errors in erlang in production? Definitely not. We have more run time type errors in our java code. Unfortunately we don’t have any ocaml code in production for comparison.

6 Likes

Mostly JVM. It solves the main problem OCaml has right now: absence of libraries for many common things. It’s also an opportunity to write those libraries, of course :smile: But for adoption, it’s quite problematic. I think Java and .Net developers are pretty much the same crowd, since I myself and a lot of friends migrated either way.

Not that powerfull, but still useful. I think it was the right solution for many problems people tried to solve with type providers, for example. Creating internal DSLs was also easy. But not comparable to OCaml, of course, I believe it’s pretty much unsurpassed on this front by any common static language.

I tended to use them much more than Scala’s equivalent in practice, though. I think I have matchers in couple of places now, but in old F# days I got a lot of mileage of active patterns. They also make some kind of internal DSL, quite easily and nicely.

I always wanted to declare a “protocol” for actors systems. Not the types of messages separetely, but something like

Ping() => Pong()
# or something more complex  
Activate(recipient: Selection) => 
  | Activated() 
  | Error(reason: :no_connection | :insufficient_resources | :timeout)

PerformQuery(query: QueryAST) => 
  | RowsResult(...)
  | TimeseriesResult(...)
  ...
  | Error(reason: :wrong_syntax | :timeout | :db_error)

If you can define specs like this for your actors, and compiler makes exhaustiveness checks, it may be quite nice, but I don’t belive you can make it sound in every case. At some point you’ll need to have some wiggle room + there should be some way to incorporate versioning into that. “Migrating” types is pretty much open problem still…

Yep, it’s somewhat dangerous and sometimes used inappropriately but very nice feature indeed.

Oh, only bad thing - I think most people nowadays don’t even know what Forth is xD But I’d be glad to see that, it’s interesting for sure!

Yep, library story in Go is one of the best in new languages.

That right here! Mutability is to blame :smile:

I think it’s improving slowly, but the decision to have basic async done in separate competing libraries is a mistake. Having standard futures across the whole ecosystem simplified working with Scala so much. I expect to see the same kinds of problems that Scala had before Futures were normalized in Rust pretty soon.

I’d rather it just had actors and better docs :smile: I hope that OCaml will eventually have both.

Oh, so I’m not alone after all! :smile: Yep, I believe production errors are the only ones that actually matter, errors during the development process - not so much, they are mostly local, so you know how to fix them quickly. And Erlang/Elixir still performs quite a lot of validations on compile, even without Dializer, like checking structs/records usage, that functions exist in modules, etc. Catches a lot of typos.

4 Likes

The heck?! Isn’t it statically typed? o.O

Or are you using the void-style interfaces everywhere?

I’d never gather that! I could use the Go styles in C via libdill or libmill if I really wanted. ^.^;

Yeah there are a lot of those libraries currently, but they are making new things in rust at quite a good rate, fixing a lot of bugs they find in the process of the original libraries. :slight_smile:

Sure there are, you can use the C libraries straight, you don’t need intermediary libraries to them, that is how its ecosystem works, don’t duplicate what already exists.

Thankfully you don’t find a lot of exceptions happening in the great majority of libraries, people prefer option and such error handling, and the few cases exceptions do happen it’s usually pretty obvious, like getting a value of a key from a map, if it returns a value and not an value option then it is pretty obvious it can throw an exception. ^.^;

As do I, or I would not be using the BEAM VM near as much as I do, but leaving out static typing is leaving out a huge boost to overall productivity.

There’s been a couple, alpaca is the current ‘method’ still in dev, but I don’t like that they aren’t black boxing the message types and others…

Exactly, this is why I firmly think that messages need to be black boxed…

How would it be dangerous? And it’s not really used inappropriately, in fact the row typing in OCaml is almost never used as static records are easier to use. Really, looks at the entire ecosystem, I’d wager it’s used potentially even less than 1% of 1% of the time. ^.^

It’s just a playground project, not designed for ‘real’ use (maybe someday), and incomplete since work got busy again, but see the tests at: safe_script/test/safe_script_ex_forth_test.exs at master · OvermindDL1/safe_script · GitHub

+1 !

It essentially is standardized in Rust. The way Rust works is they test in libraries first, then absorb the ‘best’ pattern into the language itself, and the Threading library has already been chosen (forgot the name). :slight_smile:

MC/Effect OCaml will! ^.^

Very much! And these happen far more with Elixir than OCaml in all my projects. Usually just weird errors like user input being parsed and then failing due to it not matching or stupid little things like that (I have to parse a lot of custom formats at work). In OCaml the parsers force me to handle the failure conditions far better, no option otherwise.

A lot of my typo’s are not things like lsit != list, but rather more like user_map_params != parsed_user_map, still valid, still a map, but entirely wrong format of map.

4 Likes

BTW, I think Java misses a lot of type safety because of erasure and inconsistent co/contra-variance in collection classes (though some of it was fixed, I believe). The main problem for me with Java/C# were always NPEs. In C# there is Nullable things now, which kinda help, but not really, because you have so much code in .Net that don’t use them.

Plus, most “static type systems” in popular languages are unsound and since mutability is not restrained/explicit, you tend to trip over yourself constantly.

I agree that in OCaml people tend to use them where they are really needed. It mostly applies to people new to it. Real World OCaml does a great jobs of explaining where they are useful and showing of some examples of good usage, so I think it’s less common now.

“Danger” arises when you sometimes have several records/rows with fields with the same/similar names. I did have some errors because of incorrect type inferrence, or, more precisely, type inferrence was correct, I was incorrect with my assumptions :smile:

Yeah, I wouldn’t attempt to write anything “production” in Forth, and I doubt that many people will, but for sentimental value only, it’s extermely cool! :slight_smile:

I think it’s Tokio. It does look nice, and may be a good standard default choice. Plus, it seems, there’s more projects popping around it constantly, but I’m not sure if they decided to use it as standard yet.

Yeah, I thought about it too. I have several places, where I’d like exhaustiveness checks very much. Sadly, Dializer is usually more trouble that it’s worth…

I use Ecto a lot for pretty much any validation I do. It’s somewhat heavy sometimes for it, but it prevents a lot of errors like this.

3 Likes

Precisely yes. Even Generics lose all type safety at runtime (because the bytecode performs unsafe casts).

Similar situation in Java, Java8+ added the Optional to solve the same issue, but it is still opt-in. Both should have been baked into the languages from the beginning, I don’t know what the JVM and .NET authors were high on at the time they designed the languages without such null handling protections… ^.^;

Indeed, that is why I don’t consider C++/Java/.NetThings/etc… as strongly statically typed.

Eh, even then they are harder to use then just using records as they require more annotations and work (and using the weird # operator all over ^.^;), so even newbies taught in classes at the college I work at still don’t prefer them and instead prefer static records.

That still should not really be an issue, they are not row-typed based on just the name but rather the name and types of the fields/methods, and since the type only matters when you actually use it in the function then that is checked in any case (unlike Haskell where things get more fishy because typeclasses…).

Heh, I’ve written a lot of FORTH interpreters in the past, but in this case I wanted to write one that supported macro’s and code generation, and it does indeed work! :slight_smile:

Ah I think that is it, it sounds familiar.

I keep up by following the Rust RFC lists and as I recall they are pretty well set on that one.

It catches a few cases at least, positive typing checks are still better than no checks, but yeah I would far prefer exhaustive HM checks.

I still think Ecto’s Changeset functionality (refined and enhanced) needs to become it’s own first-class Elixir-supported library distinct from database functionality. :slight_smile:

5 Likes

Well, with type errors I mean errors a strong type system would have caught. But things like problems with nil, problems with variable shadowing, no way to pass immutable references (for example when slicing) which further down the track gets modified. I guess I get these errors because I am used to immutability. When writing in C I am more aware of these things but in go (being a new language) I tend to lean a bit too much on the compiler.

Yes, I agree with this. This has been discussed in another thread but I couldn’t find it.

Tying validation into the database layer is just too coupled for my taste.

Yes, I’ve tried alpaca but it is in early development and I am not clever enough to work on core compiler things. I’ve read about a few people (including you) wanting to do an erlang backend for ocaml which would be awesome. I tried to look into how to even get started here but after looking after documentation and glancing at bucklescript I could still not figure out where to start :smiley:

4 Likes

Well Rust is mutable and it can handle all that. :wink:

Bucklescript more of forked the compiler to add it, which is a bit more painful than really needed (they want to add ‘more’ stuff that is not quite backwards compatible irritatingly). js_of_ocaml is low level but it translates the bytecode over. Or could just write a PPX and translate it over with full type knowledge. :slight_smile:

2 Likes

Fully agree! Though, Ecto is so “standard” in the community, I don’t think that there’s a need to actually merge it to the language, or something. But exposing some additional syntax to simplify writing non-db based validations may be nice. Hm, that actually can be done in a separate lib as well… ^___^

2 Likes