239

Here's an unordered list of type system features available in Haskell and either unavailable or less nice in Java (to my knowledge, which is admittedly weak w.r.t. Java) Safety. Haskell's types have pretty good "type safety" properties. This is pretty specific, but it essentially means that values at some type cannot wantonly transform into another type. ...


90

I know that this is meant to be a fairly contrived example to demonstrate the idea at play. But I would say that as a rule of thumb, you want to exhaust every possible option before relying on Subtype polymorphism. Using composition is a better solution here just based on the domain. Marriage does not define a "type" of person any more than race, wealth, ...


81

Full type inference. You can actually use complex types ubiquitously without feeling like, "Holy crap, all I ever do is write type signatures." Types are fully algebraic, which makes it very easy to express some complex ideas. Haskell has type classes, which are sort of like interfaces, except you don't have to put all the implementations for one type in ...


69

In your example, you don't really show the same message, you show two different messages that happen to have the same name. Polymorphism requires that the sender of a message can send it without knowing the exact recipient. Without seeing evidence that the caller can do something like shape.draw() without knowing whether shape contains a circle or a ...


65

a :: Integer b :: Maybe Integer c :: IO Integer d :: Either String Integer In Haskell: an integer, an integer that might be null, an integer whose value came from the outside world, and an integer that might be a string instead, are all distinct types - and the compiler will enforce this. You cannot compile a Haskell program which fails to respect these ...


36

Stream is great example of polymorphism. Stream represents a "sequence of bytes that can be read or written". But this sequence can come from file, memory, or many kinds of network connections. Or it can serve as decorator, that wraps existing stream and transforms the bytes in some way, like encryption or compression. This way, the client who uses Stream ...


33

This is a good question and it's the kind of trouble a lot of people when trying to understand how to use OO. I think most developers struggle with this. I wish I could say that most get past it but I'm not sure that's the case. Most developers, in my experience, end up using pseudo-OO property bags. First, let me be clear. This is not your fault. The ...


33

Polymorphism is the ability to have objects of different types understanding the same message This seems like a rather poor explanation of polymorphism to me. Technically correct but not very helpful in explaining the usefulness of it. Basically it's backwards to how polymorphism really gets used. So we can change your example to be like so: circle1....


31

Lots of people have listed good things about Haskell. But in answer to your specific question "why does the type system make programs more correct?", I suspect the answer is "parametric polymorphism". Consider the following Haskell function: foobar :: x -> y -> y There is literally only one possible way to implement this function. Just by the type ...


29

To answer this, you first need a definition for "syntactic sugar." I'll go with Wikipedia's: In computer science, syntactic sugar is syntax within a programming language that is designed to make things easier to read or to express. It makes the language "sweeter" for human use: things can be expressed more clearly, more concisely, or in an ...


23

The best article I've ever read on the topic was James Shore's. I've been doing "DI by Hand" for ages, as part of abstraction and polymorphism. So after I got into the professional world and I kept hearing that term being thrown around I had a large disconnect between what I thought the word should mean and what it actually means: "Dependency Injection" ...


22

The person, whether married or not is still the same person. Morphing it to another kind of person with a copy replace approach does not maintain this fundamental identity. Several other alternatives could be considered: the state pattern as already suggested by candied_orange allows to keep the same person, but use composition over inheritance to ...


20

The concept you initially refer to in your question is called covariant return types. Covariant return types work because a method is supposed to return an object of certain type and overriding methods may actually return a subclass of it. Based on the subtyping rules of a language like Java, if S is a subtype of T, then wherever T appears we can pass an S. ...


19

TL;DR Attempting to use composition first, before attempting to use inheritance, prevents naive mistakes. Also, Class Inheritance: Is easy to misuse. Is less versatile than composition. Is less versatile than interface inheritance. Requires more maintenance than composition. Provides some good guarantees about the derived types. Consider if it is worth the ...


18

Depends. Unfortunately there is no generic solution. Think about your requirements and try to figure out what these things should do. For example, you said in the morning different animals do different stuff. How about you introduce a method getUp() or prepareForDay() or something like that. Then you can continue with polymorphism and let each animal ...


18

Your example is a bit too complicated to make your point. You suggest dynamic dispatch, which actually works pretty much like that... if types get in the way and compile-time is a thing, name-mangling helps resolve identification and entity uniqueness. What you describe as accidental polymorphism is only possible at the symbolic level. In the conceptual ...


17

A related SO question. I assume you can do the same in haskell (i.e stuff things into strings/ints that should really be first class datatypes) No, you really can't - at least not in the same way that Java can. In Java, this sort of thing happens: String x = (String)someNonString; and Java will happily try and cast your non-String as a String. Haskell ...


17

public interface IDockable<T> { public void Dock(T config); } By having a type parameter, you can specify the parameter you want to accept within the Dock method in your classes. Example: public class DockerMachine : IDockable<DockerMachineConfig> { public void Dock(DockerMachineConfig config) { } } public class DockerContainer ...


16

The reason instanceof is discouraged is that it's not OOP. There should be no reason for the caller/user of an object to know which concrete class it is an instance of beyond which type the variable it is declared as. If you need different behavior in subclasses add a method and implement them differently.


16

If you can't think of a good reason TO use dynamic, then you are foregoing potential compile time checks for little to nothing in return. I prefer generics over object, and prefer object over dynamic, unless I need to interact with a dynamic language ScriptEngine or a dynamic container like a web form where its reasonable to handle the potential runtime ...


15

You can use a visitor pattern: interface QuestionVisitor { void multipleChoice(MultipleChoice); void textBox(TextBox); ... } interface Question { void visit(QuestionVisitor); } class MultipleChoice implements Question { void visit(QuestionVisitor visitor) { visitor.multipleChoice(this); } } Another option is a ...


13

As Amon pointed out, this is a good application for the visitor pattern. Using it, your AI classes will end up looking something like this: void decide(HomeSquare square); void decide(WorkSquare square); void decide(ShopSquare square); And your squares have an accept function that looks like: void accept(AI ai) { ai.decide(this); } That lets you use ...


13

The term syntactic sugar typically refers to cases where the feature is defined by a substitution. The language doesn't define what a feature does, instead it defines that it is exactly equivalent to something else. So for example, for-each loops for(Object alpha: alphas) { } Becomes: for(Iterator<Object> iter = alpha.iterator(); iter.hasNext()) { ...


12

Interesting question, I tested it this way: Superclass public class ClassA { public static void printStatic(){ System.out.println("hi static from A"); } public void printDynamic(){ System.out.println("hi dynamic from A"); } } Subclass public class ClassB extends ClassA { public static void ...


12

You have two good answers already; a third reason to stick with the property is that the pattern you are describing is a "one shot" pattern. Everything goes pear shaped when you add a second Boolean. We begin with: public class Sample { public bool IsRelevant { get; protected set; } } and we refactor this into: public abstract class Sample {} public ...


12

Don't avoid things just because they are considered evil - understand first why they are considered evil, and then decide how to avoid that evilness. You are warned about these evil things because they are usually the easy, straightforward way to solve the problem - otherwise people wouldn't always attempt to do them and the warning would be redundant. The ...


12

How to go ahead with cases in which ONLY one derived class needs to implement a method from a common interface? If you end up in this situation then generally you have a problem with your design and should refactor. For example in your calling code you call multiple methods on the class and make decisions based on the results of these methods. This is ...


12

The problem is we can't modify the components to implement a polymorphic method to display the correct window since it's a extern library. You may not be able to modify the component, but you can almost certainly compose them to produce the same effect. Pseudo code, adapt to your favourite language: interface IComponent { void display(); } class ...


11

The first thing that I'm going to suggest is that you take a few moments to read some of the other questions and answers on inheritance vs. composition that are here on Stack Exchange. There are several linked on the sidebar, for example. I'll just address your first example: Inventory shouldn't inherit from Product.(Are you selling an inventory? How do I ...


Only top voted, non community-wiki answers of a minimum length are eligible