50

Does it support concepts like separation of declaration and implementation (interfaces and classes in Java)?

How about restricting access (like access modifiers in Java)?

4
  • 30
    Note that if you're working in Haskell, you shouldn't try to write a Java program, and vice versa. Working with the language, instead of against the grain, will generally produce cleaner code. Commented Mar 24, 2011 at 4:08
  • 1
    Here's a small exercise I did that tries to mimic a few of the OO features. gist.github.com/877617 However, it was nothing more than an exercise. I wouldn't write Haskell in a Java style. Commented Mar 24, 2011 at 9:15
  • 6
    There are some great answers below, but I'd suggest you not think of things like this as "OO" features. In Haskell, for example, the main unit of encapsulation and hiding of implementation is the module, and is not tied to any specific data structure. Modular design was a good thing before it was ever used in object oriented programming! Similarly, type classes in Haskell specifically reject the OO-ish idea of writing the data structure and its behaviors in one place, but still effectively separate interface and implementation. Commented Mar 24, 2011 at 16:59
  • 1
    AFAIK even in C you divide declarations and implementations. Also access restriction isn't really an OOP concept. Data hiding may be, but that's more about how things are used than what restrictions are imposed by the language. Commented Dec 11, 2014 at 12:52

5 Answers 5

62

How do you separate declaration and implementation in Haskell?

In Haskell you can define a typeclass, which is rather different from an object oriented class so don't let the name fool you. Using the keyword class, you can declare function names and type signatures which can be instantiated (implemented) elsewhere for a particular data type.

For example, the Hashable typeclass defines the hash function, which can turn any instantiated data type into an Int. Have a new, funky data type you want to be able to hash? Fine, make an instance of Hashable. The most common data types are instantiated by the module that defines Hashable (see the linked documentation for 'Instances').

Typeclasses aren't the only way to define an interface. A method that is often under-rated is a plain old data structure. Because Haskell has first class functions, you can define a data structure that has functions as fields:

data ShuttleInterface =
  SI { launch    :: Delay -> IO Handle
     , deploy    :: Payload -> IO ()
     , getStatus :: IO Status
     }

And your functions can build or consume this data structure:

deployAllSensors :: ShuttleInterface -> IO ()
deployAllSensors shuttle = do
    status <- getStatus shuttle
    let notDeployed = filter (not . deployed) (sensors status)
    when (isOrbiting status) (mapM_ deploySensor notDeployed)

-- we used the well-known Haskell functions: filter, not, , when, mapM_
-- and some supporting functions were assumed:
isOrbitting :: Status -> Bool
deploySensor :: Sensor -> IO ()
sensors :: Status -> [Sensor]
deployed :: Sensor -> Bool

How do you restrict access to data in Haskell?

To provide abstraction, Haskell uses Algebraic Data Types. To protect fields developers declare a data type but don't export it's constructors - instead they only export a set of safe primitives that maintain desired invariants.

For example, the Map module provides a balanced tree. It couldn't guarantee balance if anyone could just declare a Map using the primitives of Branch and Leaf, so the makers didn't export those. Construction of a map must rely on what is exported from Data.Map (and those have access to/use the constructors by virtue of being in the same module) such as fromList, empty, singleton, and a whole bunch of modifiers.

Sign up to request clarification or add additional context in comments.

6 Comments

+1, Perhaps it is good to point out that, since all data is immutable, protection of fields is, though possible, not nearly as important as in OOP languages with mutable data types.
I found another useful example of "OOP-like" syntax in Haskell: stackoverflow.com/questions/24235757/…
@Ingo what is necessary is not the ability to prevent modification, but the ability to prevent depending on. Like sun.misc.Unsafe has shown. Arguably, OOP is about abstracting the internals.
Hiding implementation details in modules is still good practice even if you have immutability.
It is very important, to note, that type classes are NOT a replacement for OO classes or OO interfaces (like in Java)!! They may be named and look alike, but thinking you can use one for the other will end you up in a huge mess. Trust me; I went down that road.
|
26

See Haskell's Overlooked Object System by Oleg Kiselyov and Ralf Laemmel for a detailed explanation of how OO concepts can be implemented in Haskell. But as Antal said in the comments, don't try to write a Java program in Haskell.

Remember that objects are a poor man's closure, and closures are a poor man's object.

6 Comments

You can think of a closure as a one-method ad-hoc object; just like an object it wraps up a bunch of data with a dynamically bound function that is going to use it. So to an OO programmer a closure looks a bit like a very limited kind of object. On the other hand if you want to create a closure-like thing in Java then you need to create a special base class and then a new descendant for every version of the closure. So from a functional programmer's point of view an object looks like a very clumsy and mandraulic kind of closure.
Or maybe objects and closures provide the same functionality and we're all poor men ;-)
@PaulJohnson Your link is broken. Can you give the actual name of the paper?
@dylan, I believe Paul J. was referring to "Haskell's overlooked object system", which one can reach here from arXiv.org.
I edited the comment to include the name of paper and link, per @caya 's helpful comment.
|
5

Type classes are indeed the only constructs that remind remotely on OO concepts - in this case, on interfaces. Though, unlike in java, type classes are not types.

One good thing about type classes is that I can make totally unrelated, already existing types members of a type class. Whereas in java, sometimes one thinks: These classes A from package org.a and B from com.b that I am using ought really be implementing interface Y from a third package, but there is no way to do it that would not require a lot of boilerplate code, additional indirections, marshalling etc.

BTW, as an elderly programmer I'd like to note that "separation of declaration and implementation" has per se nothing to do with OOP. Just because most OO-langugaes support it does not mean the concept was not well known for a long time before OO was invented. Interested youngsters who think that programming before mainstreaming of OO must have been on a "stone age" level may look up MODULA, for example, where separation of declaration and implementation is not only possible, but enforced by the language.

Comments

3

One thing might be good to mention is lenses. They allow you to write the kind of a.b.c.d.e "expression" in a compose-able way.

The . can be defined for each data structure. So in some sense the . is a first class citizen in Haskell. It can be named, stored, two .-s can be composed, etc.

Comments

0

I just discovered sth by accident, see https://github.com/complyue/ooh for a runnable program with full machinery (full code is still extremely short though).

I never imagined OO stylish program can be written in Haskel in such a way so straight forward!

Constructing object:

!o <- classC $^ (777, "hahah")

Calling direct methods:

  cx0 <- o $. getNumC $ ()
  o $. setNumC $ 888

Calling base methods:

  bx0 <- (o $.. cast'C'as'B) getNumB ()
  (o $.. cast'C'as'B) setNumB 999

Method arguments have to be uncurried as prototyped here, I suppose it's the preferable flavor when writing OO style code though.

While the object class definition appears verbose as hand-crafted for now, I believe Template Haskell has much to offer for better syntax sugar.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.