5 ms·
I think folks are lost in the weeds of criticizing the specifics of the example code and not paying attention to the larger design message - that being F# provi
by thoth 11y ago
I think folks are lost in the weeds of criticizing the specifics of the example code and not paying attention to the larger design message - that being F# provides language constructs that make it easier to avoid allowing illegal states, and the type system will help detect that during compilation.
Yes it is a contrived example, yes you can write "better" C#, but this is a short example for illustrative purposes.
I bet if somebody wrote a blog post about Djikstra's letter "GOTO considered harmful" 45+ years ago, attempting to illustrate it with more examples, it would have collected similar comments: nothing wrong with GOTO, I can use it correctly; that example of spaghetti GOTO code is poor and not idiomatic; the example code is too simple and nobody would write it that way; yes it takes discipline to use GOTO without ill effects but nobody would accidentally/maliciously subvert my GOTO hierarchy; etc. Meanwhile, the original point about structuring code using different techniques to help avoid problems (and avoid GOTO) would be lost.
It's like people are overly defensive about language features (or lack thereof) as if writing extra boilerplate and not letting the compiler help is a badge of honor.
EDIT: clarity
- thomasz 11y agoI think that is highly questionable. Sum Types are a different approach with some advantages and some disadvantages over inheritance. Nothing more and nothing less. They really shine if you have clearly defined types that seldom change. On the other hand, discriminated unions make it absurdly complicated to defend against some errors that are almost comically easy to avoid by using a standard OO approach: class Range { public int From {get;} public int To {get;} public Range(int from, int to) { Assert(from <= to); From = from; To = to; } }
- kvb 11y agoYour particular example doesn't seem especially object oriented (e.g. it looks like a simple data type with a "smart constructor", which is a common pattern in, say, Haskell, too). But in any case F# supports both discriminated unions as well as normal OO design, while C# supports only the latter, so in that subset of cases that are better modeled by DUs F# will be strictly better, and in the rest of the cases it won't be worse.
- thoth 11y agoNobody says you have to use sum types to solve all problems in the design domain - and as kvb points out, F# does have OO functionality too. Your proposed problem might be better solved with the Option type and a simple guard to return None if out of range. >comically easy to avoid using a standard OO approach This is an ironic statement given that your code, as written, is circumvented by subclassing Range and side-stepping its constructor. I suppose you actually meant "sealed class"... but we're getting off in the weeds again, missing the fundamental point of the post.
- thomasz 11y ago> This is an ironic statement given that your code, as written, is circumvented by subclassing Range and side-stepping its constructor. You are the second one who says this. I must admit that I do not understand how this would be possible. The properties are not virtual, and not writable for anything but the base constructor. To my knowledge, it's impossible avoid the base classes constructor by subclassing. I'm pretty sure you can actually circumvent the assert, but you would have to use the heavy weapons in the reflection API. class Range { public int From { get; } public int To { get; } public Range(int from, int to) { Assert(from <= to); From = from; To = to; } } class LolRange : Range { public LolRange() : base(0,1) { From = 1; To = 0; } } Error CS0200 Property or indexer 'Program.Range.From' cannot be assigned to -- it is read only Error CS0200 Property or indexer 'Program.Range.To' cannot be assigned to -- it is read only