4 ms·
> it's frowned upon to use type inference for return values in method signatures The language shouldn't allow it in the first place. Its a symptom or not balan
by MrBuddyCasino 6y ago
> it's frowned upon to use type inference for return values in method signatures
The language shouldn't allow it in the first place. Its a symptom or not balancing power with complexity and shows up elsewhere in Scala. They "were so preoccupied with whether or not they could that they didn't stop to think if they should."
- logicchains 6y agoOCaml also does global type inference like this, and it generally works out fine (unlike Haskell, it's not idiomatic to write a type signature for every single top level function in OCaml). Maybe because the type system is more principled compared to Scala.
- momentoftop 6y agoOcaml and the MLs have a very strong commitment to global type inference, much stronger than Haskell's. Scala has no commitment. That said, you do see a lot of types in Ocaml code. Ocaml source files typically have an accompanying signature file (with extension ".mli" rather than ".ml"). The signature file gives explicit types for all of the definitions (fields) in the structure file. Often, you need to write these signature files because you want to hide implementation details from the user and so give narrower types than the ones inferred by the compiler. You can and do write Ocaml without ".mli" files, and there, you are relying heavily on global type inference, and built-in Ocaml tools to tell you what your most general ".mli" file would look like. You can and do get the compiler to write them for you and then add your restrictions and documentation. As such, Ocaml programmers are very used to reading these signatures as the entry point to understanding a library. This doesn't work so well in Haskell, because Haskell doesn't have global type inference, and annotations are sometimes mandatory. Consider the expression show (read "1") Without saying what type "read" is supposed to return here, there's no way to know what this code is supposed to do.
- MrBuddyCasino 6y ago> Ocaml tools to tell you what your most general ".mli" file would look like Thats a nice idea! Can those tools do automatic refactorings to use the generalized type?
- momentoftop 6y agoAh, sadly I haven't come across any refactoring tools for Ocaml. But in Emacs with Merlin, I regularly hit "C-t C-t" on a module identifier, and it brings up the signature in another window, whether there is an ".mli" file or not.
- logicchains 6y ago>because Haskell doesn't have global type inference I'm curious what you mean by that. Is it because Haskell's additions mean that its version of Hindley-Milner type inference is not able to infer types for all expressions? Is this also why the OCaml Emacs mode is much better, even though Haskell has more developers?
- momentoftop 6y agoIn part, that's right. For example, there is an extension called "rank-n" types where global type inference is provably impossible. But even in Haskell 98, type classes often create ambiguities that mean the compiler doesn't know what code to generate, as in the example I gave with show (read "1") You fix these with annotations. I couldn't say why Ocaml's Emacs mode is so much better. Merlin was a game changer for me, and I've never had issues getting it to work. ghc-mod is the equivalent in Ocaml, but I've never managed to get that to work.
- tome 6y agoI'm curious what about Ocaml's Emacs mode is better. I use dante for Haskell in Emacs which is good, but I'm always interesting in hearing about better technologies.
- momentoftop 6y agoI'm not the parent, but thanks for the link to Dante. One of the main things I like about Ocaml and merlin is how robustly it can tell you the types of expressions by hitting "C-t". It usually works on incomplete code, and it will tell you the type of arbitrary subexpressions (not just identifiers) in your selected region. It will do automatic destructuring of an identifier (producing a match/case expression with the patterns in the ADTs filled in for you). It's not perfect, but I use it a lot for complex ADTs. The autocompletion is great too. It will complete for local variables in scope, and it must be having to do some fairly complex stuff in the background, since it'll autocomplete for local modules applied to functors. For example, you can write let foo x = let open Foo(Bar) in ... and when you autocomplete inside the "...", it will bring in completions from the module generated by applying Bar to Foo. I'd be interested to hear how dante compares.
- deleted 6y ago[deleted]
- ghostwriter 6y ago> Ocaml and the MLs have a very strong commitment to global type inference, much stronger than Haskell's This is hilarious to read when (+.) is a thing in OCaml > Without saying what type "read" is supposed to return here, there's no way to know what this code is supposed to do. It has nothing to do with global type inference, as "1" can successfully and meaningfully be parsed into several distinct types, like Int, Integer, Float, MyCustomEnum at the same time, where each of them has their own implementation of `Show`. You cannot "magically" infer that globally, unless you introduce an equivalent of (+.) for disambiguating parsing, which would serve the same purpose as the explicit type annotation passed to the parser.
- valenterry 6y ago> The language shouldn't allow it in the first place. Its a symptom or not balancing power with complexity and shows up elsewhere in Scala. To me it rather seems you have not used some of Scala's feature which are not really usable without return type inference. E.g. typelevel computations where the return type depends on the inputs. Of course rusts typesystem (while maybe turing complete) is vastly less powerful than Scala's, so it might not have the need for it.