Dumb text analysis: Clean merges might be broken.
Many VCS consider adjacent lines to be conflicting.
No great tools.
Merge time matters hugely (cf Bors/Homu in Rust).
Patch algebras don’t necessarily produce better results (see discussion with Pijul and Darcs).
Avoids if
, prefers dispatch! E.g. CommandLineHandler, True/False.
Often invalid types: add a method call, implement it from the debugger.
TDD is integrated and delightful. Persistent test state is really valuable when working.
Refactoring is very good: rename method, extract method, move methods around. No static typing, but method names are often unique.
Code is pretty readable due to aggressive use of keyword parameters. No positional function calls!
Searching is incredibly good. Finder can search for examples. Spotter can even search for text in open windows!
Debugger is excellent. Restarting is very useful.
bad state after failed type check
team felt it adds verbosity
the extras package is very important, painful without it
horrible monkey patching in places
driven by dropbox’s needs, guido supported
distributing types is still not a solved problem
package coverage is poor (e.g. no mock on python 2)
reveal_type is cool
weird quasi-syntax in comments – syntax errors stop all progress
limits package usage (e.g. couldn’t use sh)
only caught a few bugs
- mostly None dereferences
lovely for refactoring (adding an extra argument), and ipython/IDEs are gradually taking advantage of the annotation info
guarantees are not very strong
in
basically ignores typingtype: ignore
is dangerous- empty functions can be any type!
- easy to get caught out by unicode/string interpolation differences
optionality is nice
- choose whether to worry about None
- don’t both annotating types on tests
Similarly, dumb-jump is very Emacsy.
Can’t use Ctrl+F in a settings page, or a search results buffer in your average IDE
Funky syntax.
Copying gotchas.
OO model is nice.
Amenable to static analysis.
Privacy model is elegant.
blue ocean
pipeline ecosystem
plugins are immature
Better to think about collections of features.
Go-to definition (impossible in Python, e.g. the sh library)
Code completion on typing . (doesn’t require type safety, cf Go)
Finding incompatible function composition (common in statically typed languages, but eslint on underscore can do this too)
Requiring local variable annotation (old C++, pre Java 10): enhances local reasoning, affects variable names, affects development without IDE support, increases verbosity
Requiring function type annotation: aids tooling, prevents surprising action at a distance (e.g. Haskell)
Requiring effect annotations (Haskell IO, checked exceptions in Java, nothrow in C++, possibly elixir/nim?)
Enabling optimisations (possible in C++, LLVM, Rust, Julia, not possible in type-erased Java)
completeness checking with unions / case statements.
Generally excellent.
Compiles are fast. opam is good. Community has standardised around jbuilder/dune. Merlin is excellent, and I hear good things about lsp-server-ocaml too. utop is great.
Emacs tooling is good, but Stefan Monnier (sp?) has worked on it, so not a great surprise!
Could use more linting.
A whole different family (ML), so experience isn’t always sufficient.
let foo = 1 (* value ) let foo x = … ( fn *)
let bar x y z = … let baz = bar x y (* also fn *)
let () = … (* used for side effects! *)
Community is very helpful when you get stuck.
Needing let rec is a gotcha.
Some gotchas around nested match statements.
Surprising [1,2] in lists.
The reasonml page gives a good overview of gotchas in its comparison page: https://reasonml.github.io/docs/en/comparison-to-ocaml
Generally works nicely.
Very little type annotation. Use merlin when you want to know the type.
Lazy!
Printf.printf “%a” [1;2;3]
shows ‘a list rather than int list
Structural!
Structs are just bundles of fields, not nominally typed.
Pushes you to use immutable vars and recursion.
Having refs is nice, as you can use a few mutable variables if it suits you.
(* Read all the lines from stdin until EOF. No concern given to
efficiency. *)
let read_all_stdin () =
let text = ref "" in
(try
while true do
text := !text ^ input_line stdin
done
with
End_of_file -> ());
!text
Syntax again here: !
means deref and and ^
means string append.
OCaml has a GIL.
Printing arbitrary types.
Picking libraries (github stars are a poor signal). Good set of choices though.
Different types of let were no issue at all.