7 ms·
This is article actually has very little to do with any particular programming language or language comparisons. I like how it logically builds up to each of it
by jfaucett 12y ago
This is article actually has very little to do with any particular programming language or language comparisons. I like how it logically builds up to each of its conclusions which summed up are the following:
1. Variables should not be allowed to change their type.
2. Objects containing the same values should be equal by default.
3. Comparing objects of different types is a compile-time error.
4. Objects must always be initialized to a valid state. Not doing so is a compile-time error.
5. Once created, objects and collections must be immutable.
6. No nulls allowed.
7. Missing data or errors must be made explicit in the function signature.
I think the writer also provides a pretty practical definition of what it means for a program to be "reasonable". Really nice job!
EDIT: I pasted the wrong list as dsp1234 pointed out :)
- dsp1234 12y agoIt appears that you copied the "F# does this" list, not the "How to make a language predictable" list. For instance, #6 on that list is "No nulls allowed" which is stronger than "Nulls are NOT allowed, in general".
- jfaucett 12y agothanks :)
- kyllo 12y agoOnce created, objects and collections must be immutable. Collections I understand, but what's the point of immutable objects? If you're eschewing mutability, why have objects at all? The whole point of objects is to encapsulate mutable state, together with methods for mutating that state. If you said Once created, data structures must be immutable I would be more inclined to agree.
- sonyandy 12y agoTo "what's the point of immutable objects?": runtime polymorphism + maintaining invariants (since immutable, at the time of construction).
- kyllo 12y agoWhy do you need objects to get runtime polymorphism? Here's a counterexample of runtime polymorphism without objects: http://clojure.org/runtime_polymorphism http://clojure.org/runtime_polymorphism
- tormeh 12y ago>The whole point of objects is to encapsulate mutable state, together with methods for mutating that state. Citation needed. I use my objects to hold immutable state with methods that does not mutate that state.
- kyllo 12y agoWhat do you gain from using objects in that way, as opposed to immutable structs and functions?
- tormeh 12y agoI program in Scala, so structs are not a thing (classes can extend/"inherit" AnyVal to be allocated on the stack, though, I think). Functions are nice, but from a pure syntax standpoint I often prefer methods because it limits the parantheses. It's especially neat when the methods take no arguments, like .toString. But yeah, otherwise there's no difference, really.
- tel 12y agoExpress your immutable objects with an interface like this push : ('a queue, 'a) -> 'a queue pop : 'a queue -> ('a queue, 'a) option In other words, instead of mandating that state updates in objects occurs via global ambient state simply cause objects to return a new version of themselves with the suitable updated state. All your standard immutability tricks now apply. Objects maintain their meaning through their opaqueness/type-abstraction.
- kyllo 12y agosimply cause objects to return a new version of themselves with the suitable updated state That's what Clojure does (and what lots of other functional languages do), only they're not "objects," they're just data structures. Again, if you're not using mutability or inheritance, then why do you need objects at all? What do objects buy you, compared to data types + functions? In the absence of those features, isn't an object class really just a module with a data type definition and some functions in it?
- tel 12y agoIt depends on what "object" means to you. Turns out this is very, very complex. A deep answer has a lot to do with laziness, F-algebras, totality, dependent types, yada yada yada. In particular, the tip of this iceberg is the difficulty of comparing functions for equality. Does any of this matter? Maybe not. Structs with recursion can get you 90% of what you want (just ask OCaml). One thing you might miss is the ability to do late binding and open recursion—up to you whether or not you care.
- kyllo 12y agoOne thing you might miss is the ability to do late binding and open recursion In the absence of objects, that's what `letrec` is for. Scheme, OCaml, and SML all have it. In Haskell `let` is `letrec` by default. Clojure has `letfn`. C has forward declarations. Without these features you wouldn't be able to write mutually recursive functions.
- geocar 12y agoThis is not a nice job. The first "issue" is that ``DoSomething accesses x directly rather than through the parameter'', but then goes on to talk about types. I think this is a big part of why we are bad at programming: A because 6 therefore Go Fish. I have noticed that when a program is small enough that I can see all of it, then I can reason about all of it, and when I cannot see all of the code, then I cannot. I may resort to note-taking or trying to remember while flipping tabs quickly, or even outright guessing, but I certainly am not reasoning about it. I do not buy that typing variables, or lambdas, or long method names (like `Equal`), or having "compile time", or `null` or "function signatures" offers anything like the gains had by able to see all of the program, so I'm disinclined to waste energy on what I view as premature optimisation.
- tel 12y agoI disagree strongly. Good types can serve as very adequate reasoning tools for programs at large. This is the source of claims in Haskell/ML/Etc where "if it compiles it works" is used to guide 90% of even massive refactoring endeavors. It can be hard to believe how useful good types can be.
- geocar 12y agoI don't understand you. Do you believe "good types" in a 1000 line program is easier to reason about than a 20 line program?
- jfoutz 12y agoCan't speak for tel, but i believe that. Types establish the rules of the game, and the compiler backs you up enforcing those rules. On the other hand, i'm the kind of guy that has read 20 lines of code and missed possible null value bugs. Sucks when you have to tell customers to wait for the next point release before they can use this new feature.
- geocar 12y agoWhy would you make a customer wait for a "point release" for a program that is only twenty lines long? I wonder if you thought I meant "a bug in 20 lines" when I meant a "20 line program". EDIT: e.g. 20 lines is enough for SQL http://web.archive.org/web/20060505221834/http://kx.com/q/e/s.k http://web.archive.org/web/20060505221834/http://kx.com/q/e/...
- mrec 12y agoI don't think 2 is especially compelling unless you've also bought into 5. For mutable objects, object identity is very important, and a default comparison that obscures it is much less appealing. I'm not arguing against those two conclusions as a pair, just with the order in which the article presents them.
- tel 12y ago> Variables should not be allowed to change their type. This is the preservation component of the formal concept "type safety". Thus any type safe language must achieve this. > Objects containing the same values should be equal by default. This one really depends on a lot of things. You may have abstract types in which case equality should not be implicitly defined. You may also have codata types where you cannot merely compare "value containment" since it's no longer a concept. These are both important things which are sometimes called "objects" and shouldn't be eliminated from languages. Really, this is a lot more complex than it seems. But at first swing: "structural equality should be everywhere and reference equality isn't a genuine concept" is pretty great. > Comparing objects of different types is a compile-time error. This is a-OK so long as it's easy to prove when two dissimilar types are actually the same. In cases where that's not true there are other forms of equality which are useful. > Once created, objects and collections must be immutable. This is a little overly strong. Regionalized mutability can be made to be referentially transparent from the outside. --- But man, yeah, this are tiny nits. This list is great.
- psibi 12y ago> Regionalized mutability can be made to be referentially transparent from the outside. Can you give an example of that ? Is that similar to ST Monad ?
- sjolsen 12y ago> You may have abstract types in which case equality should not be implicitly defined. You may also have codata types where you cannot merely compare "value containment" since it's no longer a concept. These are both important things which are sometimes called "objects" and shouldn't be eliminated from languages. I think it's important to distinguish equality from equivalence. There are many cases (e.g., enumeration types) in which equality is a perfectly appropriate definition of equivalence; but there are also many cases (e.g., some codata types) in which equality is an inappropriate definition of equivalence. Therefore, equality-as-equivalence as default behaviour is probably a poor choice— though it should be easy to opt for that behaviour. As for equality (i.e., intensional equality) itself, I think memberwise equality (or perhaps even equivalence?) is a perfectly reasonable definition. There are times when you really want to discriminate on object identity (in the storage-location sense), but you needn't restrict equality to object identity to allow that.