5 ms·
One of the features that makes F# great for organization is the sequential ordering of compilation units which makes it easier to understand code dependencies,
by sparkie 8y ago
One of the features that makes F# great for organization is the sequential ordering of compilation units which makes it easier to understand code dependencies, and makes it awkward to create mutually recursive types (requiring them to be in the same code file separated by `and`, or defined in signature files in advanced).
This might sound like an unwanted restriction, but 9 times out of 10, having mutually recursive types is signs of a code smell. You can almost always model your problem better with a slight indirection through an interface or function, it helps avoid the need for mutation, and makes testing simpler.
- algorithmsRcool 8y agoI mostly agree about mutually recursive types, but I really hate having to keep my files ordered in the project honestly. It might be my least favorite thing about F# (Except that Option<T> is a class not a struct)
- piaste 8y ago> Except that Option<T> is a class not a struct There is ValueOption<T> now. It's a mouthful and you'll still have to deal with all the standard library, or other third-party libraries, which produces and consumes Option<T>, but you can address that with some aliases and conversion operators if you want to go all-in: type 't voption = ValueOption<'t> type VOption<'t> = ValueOption<'t> let inline (!) opt = if System.Object.ReferenceEquals(opt, null) then ValueNone else match opt with None -> ValueNone | Some x -> ValueSome x let inline (?) vopt = match vopt with ValueNone -> None | ValueSome x -> Some x;; // usage let x = !(List.tryFind (fun x -> x = 0) [1]);; // [<Struct>] val x : int voption = ValueNone
- konamicode 8y agoThere is Mechanic (https://github.com/fsprojects/Mechanic https://github.com/fsprojects/Mechanic), an OSS project that's meant to take away some of the pain, though I don't have any experience using it and I'm not aware of how useful it is in practice.
- clausok 8y agoI disliked the module\file order restriction when I started, but have come to appreciate it because every time it felt like a thorn in my side it turned out that the thorn was prodding me towards a better organizational structure. I've even found that apart from enforcing better design, it can also trigger it. As an illustration, I've had a function 'f' in module 'C' that I decided made more sense in module 'A'. When I moved the function however, module 'A' would no longer compile because 'f' was dependent on a module 'B'. No problem I thought, I'll just move module 'A' below module 'B'. Whoops, now module 'B' won't compile; I didn't realize it was dependent on module 'A'. If I resist the urge to just revert everything and return the function 'f' to module 'C', and I investigate "why does 'f' feel like it belongs in module 'A' and yet placing it there introduces circularity...", often I'll discover a beneficial refactoring that I probably would not have thought of otherwise.