Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> Essentially, the fusion of [functional and object-oriented programming] can have a power that neither of the two paradigms individually can have.

I tend to disagree. OOP can borrow some FP stuff (as we see with map/each/select/reject in Ruby for instance, or lambda's in Java); or to take it broader: imperative can borrow some from declarative.

But "fusing" the two will cause FP's ease-of-reasoning ("just functions and data structures") to be lost. On top of that, when using a strictly typed discipline (like Scala does), the types will become really messy.

So when it comes to FP, I like it pure-and-typed (a la Haskell), or untyped (like the Lisps), but not mixed-paradigm.

When it comes to OOP/imperative I like to mix in as much of FP/declarative as makes sense (like Ruby does for instance).



I agree with this, but I always used scala as a OO language mixed with FP features. I prefer OO, but many in the scala community were adamantly on the FP side (7 years ago, not sure today).

About OO: subtyping leads to semi unification which really complicated type inference. I'm beginning to think it might not be a good idea to combine FP unified features with OO semi unified features.


> I always used scala as a OO language mixed with FP features

Good point! Must admit that I did not write a lot of Scala, but I always approached it from the FP side :)


I think there's a huge opportunity for FP+OO... but that OO will have to be rethought from first principles (which are lacking in OO).

More specifically, I think OO-style code interactions are great but that they need to be separated from ambient mutability, subtyping, subclassing, inheritance, etc. Late binding/open corecursion is really cool however.

I would like to see a language which starts with ML modules as a base and build a totally novel semi-OO system into FP. I don't think it would, at the end of the day, look much at all like OO the way that OO appears today, but I think it could still gather many of the advantages while maintaining ease of reasoning, good type inference, etc.


I think there's a huge opportunity for FP+OO... but that OO will have to be rethought from first principles (which are lacking in OO). More specifically, I think OO-style code interactions are great but that they need to be separated from ambient mutability, subtyping, subclassing, inheritance, etc.

This has already happened. Ideally, good object-oriented code should always prefer immutability over mutability, should prefer interface polymorphism over inheritance polymorphism, should prefer has-a relationships (the OO version of composition) over is-a relationships (subclassing), and so on. Much of this was originally figured out a very long time ago.

So the issue isn't that these standards don't exist; it's that they aren't widely understood among users of object-oriented languages. That, in turn, is because OO is so widely used by so many programmers, including a lot of people with very limited formal training in computer science, that most users of OO languages have very little exposure to any of the literature about what constitutes well-crafted object-oriented code. Certainly less so than in FP, which benefits (in this department) from the fact that it hadn't even begun to escape the ivory tower in any sort of serious way until just a few short years ago. In short, object-oriented programming is a victim of its own success.

It doesn't help that the first really widespread object-oriented language wasn't particularly object-oriented, either.


> Ideally, good object-oriented code should always prefer

Really what I'm referring to is a language which outlaws instead of one that leaves it up to preference. And by outlaw I don't mean entirely, but instead a language which requires the programmer explicitly opt into these richer domains as they are needed.

My understanding is that while these principles are understood as valuable, OO is generally constructed as too permissive to enforce them.

In a similar story, unbounded recursion is generally "bad" in almost every part of a program---nobody likes mysteriously hanging programs---but only total languages have a formalism which allows you to profitably outlaw it.

So I'm convinced there are the beginnings of the theory of objects lurking around out there even if they rarely see the light of day (really) in practice. But I also recognize that modern functional semantics grew over the last 80 years. I don't think (maybe I'm wrong) that the whole package of OO has had so long to mature.


> So the issue isn't that these standards don't exist; it's that they aren't widely understood among users of object-oriented languages.

But we're talking about language design. I think enforcing constraints is much (maybe all, from a certain point of view and definition of "constraint") of what a programming language ought to do. Haskell code is principled because the language is principled, not because of conventions passed from an ivory tower.

Also do you know of any languages built around those principles you mention? It sounds like studying such a language might make OO click for me a little more.


I feel that Golang in many ways is on that path, the way it does not allow no-subclassing really got me thinking.

> I don't think it would, at the end of the day, look much at all like OO the way that OO appears today

Won't it be more like a Actor-oriented thing then?


"I feel that Golang in many ways is on that path, the way it does not allow no-subclassing really got me thinking."

I'm pretty decent in Haskell and fluent in Go at this point, and it really depends on what you mean by that. Is Go a certain brand of very refined OO? Yes. I've even found certain ideas from PF are surprisingly adaptable [1], the "surprise" being that it's not the usual "Look, Ma, I can map/filter/reduce!" that an OO language borrows from the FP world, which Go is actually really hostile to. (Go does have closures and they are important, but the type system precludes a lot of the "good stuff".)

However, is Go headed in the direction of Haskell? No. It's definitely not. Trying to turn it into Haskell would be nothing but pain. Mutability is pretty fundamental in Go, and while there's a culture of isolating it to goroutines, the language itself does little to help with that.

[1]: http://www.jerf.org/iri/post/2923


> it really depends on what you mean by that. Is Go a certain brand of very refined OO? Yes.

Indeed that's what I meant.


I'm not certain. I think the interesting aspects would be in considering what's missing from open corecursion. I don't think the actor model is much better foundationally---it's a destination, not a beginning or a path.


Uhm...you mean like Moby?

http://moby.cs.uchicago.edu/


Perhaps, I'll take a look at it.


What is "open corecursion"?


Corecursion is when you define the meaning of a type by a coalgebra like

    x -> F x
for some pattern functor F. So, for instance, defining an infinite stream like

    newtype Stream = Stream { runStream :: (X, Stream) }
is corecursion. The interesting part is that whatever defines the stream is forced to fix the Stream type immediately. Open (co)recursion in OO langauges occurs when the recursive type is left undefined (i.e., self is passed in). This allows you to change the type of the object at every step if desired.

The similar game in a recursive function might be defining face like so

    fact :: (Int -> Int) -> (Int -> Int)
    fact recur n = n * recur (n-1)
We "tie the knot" by passing fact to itself

    fix f = f (fix f)

    fix fact :: Int -> Int
which would allow us to add extra cases as needed

    let term recur n = if n == 0 then 1 else recur n

    > fix fact 3
    -- infinite loop
    > fix (term . fact) 3
    6
So this is a kind of "mixing" of recursive functions. Open corecursion lets you do OO-like "mixing" of corecursive functions.


But look at Clojure. It's imperative yet quite FP, but much of the language rests on OO polymorphism. Clojure certainly isn't an OO language (in fact, it is decisively "anti-OOP"), but it does mix an essential OO idea, and that actually helps keep the language simple.


I would not call Clojure imperative myself. To my best knowledge it allows imperative style just as much as declarative. And having read some Clojure code before I thought that it's community kind of prefers declarative for most things.


> Clojure certainly isn't an OO language

Multi-methods and protocols


That was my point: even though Rich Hickey pretty much touts Clojure as an anti-OOP language, Clojure still relies heavily on OO polymorphism, yet it doesn't make the language any more complicated -- in fact, it helps keep it simple.


Sorry I misinterpreted it.

As someone that likes multi-paradigm languages, I tend to dislike that many FP guys "forget" their languages also do have first class support for OO when needed.

Somehow, I did not read you comment properly and spitted out a bad comment.


In Java 7 it was pretty trivial to create a closure with an anonymous class and if that anonymous class implemented Callable or Runnable it was effectively a lambda with strong types.


So you don't use type classes in Haskell?

Neither touch F# or OCaml.

Nor CLOS in Lisps.


A major advantage of typeclass polymorphism vs dynamic polymorphism is that typeclasses enable parameteric polymorphism, and parameteric polymorphism enables reasoning that is lost if types can "pretend" to be a supertype.

For instance, in Haskell you can prove a functor instance has at most one implementation (if we disallow diverging values), uniquely given by fmap id === id. GHC can automatically derive it for you. If you have dynamic polymorphism this is lost because now you can have "nonuniform" functor instances that behave differently for different types while still satisfying the functor laws.

More generally, parameteric polymorphism eliminates a large number of "behavior surprises" that can lurk in OO code. And with existential types I never find myself missing dynamic polymorphism. Similarly, in Clojure, if I find myself using dynamic behavior, it's either to interact with Java or as a hacky version of parameteric behavior.


I don't understand your example. Is there an explanation for people who aren't Haskell experts somewhere?


> For instance, in Haskell you can prove a functor instance has at most one implementation

How would one do that?


I believe the technique is relational parametricity, but I don't actually know how to apply it in this case.


Correct me if I'm wrong, but isn't OO in OCaml frowned-upon, or at least not used frequently by seasoned programmers?

Not an OCaml programmer myself, but I heard this multiple times. For example, in Real World OCaml [ https://realworldocaml.org/v1/en/html/objects.html ]), and I quote from Chapter 11:

> You might wonder when to use objects in OCaml, which has a multitude of alternative mechanisms to express the similar concepts. First-class modules are more expressive (a module can include types, while classes and objects cannot). Modules, functors, and data types also offer a wide range of ways to express program structure. In fact, many seasoned OCaml programmers rarely use classes and objects, if at all.

To be fair, the chapter goes on to explain why you'd want objects. It also states they are very different from objects as understood by other OO languages. I'd say OCaml is therefore a bad example for OO.

--

How are type classes in Haskell an OO feature?


The fact that OO is not used frequently in OCaml does not mean that it is useless. Objects in OCaml are typed structurally, not nominally, i.e. object's type is the set of the methods it provides.

Consider an example:

  let a = object method f x = 1 end;;
  val a : < f : 'a -> int > = <obj> 
We define an object a, and the interpreter tells us that the type of the object is "< f : 'a -> int >", i.e. it provides method f.

Define another object

  let b = object method f x = 2; method g x = x end;;
  val b : < f : 'a -> int; g : 'b -> 'b > = <obj>  
Define a function that takes calls method f of its argument:

  let f obj = obj#f ();;
  val f : < f : unit -> 'a; .. > -> 'a = <fun>
The type of the function tells us that its argument must be an object that provides method f, and maybe some other methods. Now, we can call this function with object a, and object b:

  f a;;
  - : int = 1  

  f b;;
  - : int = 2 
This structural typing, (or if I'm not mistaken, it's called row polymorphism) is an interesiting feature of the language, and it may be useful in some situations. It does not harm the rest of the language, and I see it as a good feature that probably does not get a lot of attention, but it's theoretically solid and works well. Compared to more usual OO systems, it is cleaner and, imho, easier to reason about.

That said, I think, the authors of "Real World OCaml" are right, encouraging the use of Modules rather than Objects. But they do so primarily because in many mainstream languages the main means of abstractions are objects, and they are used for everything. OCaml has functors, modules, it has records, it has ADTs, it has functions, so the need for objects is very limited, and so the new users must get this message very clearly.

An article on objects in OCaml: http://roscidus.com/blog/blog/2013/09/28/ocaml-objects/


Awesome, thanks for the explanation!

I think I understand the appeal of structural typing: you are defining implicit anonymous interfaces as you write objects, and automatically grouping objects that share structure. But in which case is this more useful than, say, defining type classes or using explicit interfaces in mainstream OO languages? Or is it a case of preferences?

I can see a difference with objects: in most mainstream OO languages you cannot retrofit an object to comply with the interface you want if you don't control the source code and the object only differs from what you need on a triviality such as naming. But what about type classes? Isn't this what they are there for?


> How are type classes in Haskell an OO feature?

See https://news.ycombinator.com/item?id=8280613

There are so many ways of doing OO.


Depends on how you define OO. My own definition of object involves identity and corresponding encapsulated state, which is something that Haskell doesn't support directly (since identity isn't pure).


Sure, but given your backgound, I imagine you are fully aware that back in the early 90's the OO community was quite divided about what are actually the core concepts and their implementation.

So, what OO is all about will depend which researcher gets asked.


Oh, fully agreed. I think my main point was that OO in a language such as OCaml has very little to do with OO in a language such as Scala (or Java). I'm agreeing with the OP that the marriage of OO and FP in Scala is problematic.

Yes, we can use less currently mainstream (note: not less correct) definitions of OO, but that doesn't help the Scala=OO+FP position.


Just like languages have versions/revisions, e.g: C++11,C++14, Java8 ...etc, having versions at major changes during evolution of OO might have helped in creating reference points which can facillitate discussions and enhance understanding i.e. like OO98, 0099, OO2005 ...etc.


That's impossible, because what would you write in OOxx, given the different CS views and programming models on the subject?

Jump dump what is being worked on at any given point in time?

For me it is hard to grasp how youngsters see OO or FP, because I was part of the initial mainstream waves. So I got to see the things in a different perspective.

The world at companies was procedural, and lots of experimentation was going on.


True. And in the end, this even applies to functional or declarative programming


> So you don't use type classes in Haskell?

Sorry, how does this remark relates to my comment?


I assume it was intended to be 1) an assertion that type classes are OO, and 2) an implication that using them is mixing OO in your FP (which you said you don't like to do), and so 3) an allegation of inconsistency which should be clarified or examined.

There are a few places where this chain is weak.


> an assertion that type classes are OO

They never occurred to me as OO. Could someone explain this?


Sure, since I mentioned it.

Sorry if I misassume your OOP experience.

Many think about OOP as introduced by Simula/Smalltalk, or how it is served by Java/C#... ones.

However there are many other ways of doing OOP, which many of us in the old (early 90's) experimented with, while OOP was striving to become mainstream.

Type classes in Haskell and their use, can be easilly mapped to interfaces/protocols/traits/... in the OO world.

From the OOP point of view, type classes are a group of operations that can be applied to a given type and refereed to by a specific name.

Which allows writing polymorphic operations over types that support a specific a specific group of functionality.

Polymorphism and data hiding are the common concepts across all OOP proposals.

As for the remaining concepts, there are lots of languages that agree to disagree, between mainstream, academia and lost OOP battles.

And I can call one of the many Simon Peyton Jones talks that describe this, http://yow.eventer.com/events/1004/talks/1054, starting at 00:42.


To my mind, the biggest thing missing from typeclasses that you get automatically with many OO systems is a sense of persistent identity of objects. Of course Haskell has ways to roll your own, and I'm not sure the decoupling is a bad thing by any means, but it's a difference.


tnx. very insightful. I'm not fully convinced that type classes are OOP, but I certainly understand why --for a very broad definition of OOP-- one might think they are.


Yes.


So what are you proposing to prevent functional languages form being a complete nightmare from a modularity point of view? (See Haskell.)

Module systems aren't much more than castrated object systems, so I don't see a real benefit of picking some half-assed module system over a first-class object system.


Haskell modules may be lacking in some aspect, but I certainly dont think they are half-assed. They are conceptually very simple and the community got quite far with them.

I also dont think that Haskell-modules and objects are on the same level, for instance: Haskell's modules do not encapsulate state.


> So when it comes to FP, I like it pure-and-typed (a la Haskell), or untyped (like the Lisps), but not mixed-paradigm. You overrate pure programming.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: