Why Class?
hadihariri.com
hadihariri.com
Software design has as a fundamental problem being able to express yourself in a way that is clear and remains clear as things change. Basic principles of good software design, like reducing cohesion, remain good principles no matter what "paradigm" you think you're using. When you change paradigms, be aware that the basic principles remain the same no matter what label you give them. And since design is all about tradeoffs, if you are going to have to violate a principle, you might as well do it in the clearest and most straightforward way possible.
Let me give an example. A singleton is bad for all of the reasons that a global variable is bad. If you need one, I prefer to make it a global variable simply because that is honest about what design principle has been broken. (Unless I want to make it lazy - then it is easier to write with a singleton!)
So learn the principles. Figure out what they look like and are called in your paradigm. Get on with life and solve real problems.
Let me give a concrete example. I learned more about good OO design from the first edition of Code Complete than any other book that I ever read. Even though it was entirely about procedural programming. Because the principles that it discussed, from how to name functions to the value of abstract data types to information hiding, all apply directly to OO. And to functional programming. And to aspect oriented programming. They are truly universal. Learn the principles, they are more important than the labels.
http://en.wikipedia.org/wiki/Cohesion_(computer_science) http://en.wikipedia.org/wiki/Coupling_(computer_science)
But what's important is not the label, but the principle. :-)
But also remember that there's no one proper way of doing these things, it's all heuristics, not laws written in stone.
Why OO? Classes exist to decouple behaviors from data. In fact, their purpose is to think in terms of cohesive sets of behaviors instead of data-driven functions.
Does this apply to any possible case? No, it's a leaky abstraction.
Why FP? Functions exist to decouple behavior from other behavior. In fact, their purpose is to think in terms of completely decoupled sets of behaviors instead of cohesive functions.
Does this apply to any possible case? No, it's a leaky abstraction.
Why AOP? Aspects exist to decouple behaviors that apply across classes. In fact, their purpose is to think in terms of orthogonal sets of behaviors instead of hierarchical sets of behaviors.
Does this apply to any possible case? No, it's a leaky abstraction.
Why Procedural Programming? To separate the functionality of the application in separate behaviors. In fact, the purpose of procedures is to think in terms of behaviors instead of sequences of operations.
Does this apply to any possible case? No, it's a leaky abstraction.
Why Declarative Programming? To express solutions in terms of goals instead of behaviors. In fact, its purpose is to think in terms of desired state, not sequences or compositions of behaviors.
Does this apply to any possible case? No, it's a leaky abstraction.
Why Logic Programming? To explore the logical consequences of given facts, instead of focusing on behaviors or desired outcomes. In fact, its purpose is to find new truths starting from given truths.
Does this apply to any possible case? No, it's a leaky abstraction.
Why spaghetti code? Wait, no that's just crap ;-)
For instance, I'm sure there must exist problems that require inheritance, polymorphism, encapsulation and implicit state mutation, but those are such weirdly specific requirements that I don't think OOP is applicable in most of the cases where it's in use.
I agree that some paradigms are more useful then others. Its rare to use declarative and logic based languages. (i assume declrative here means where u declare a goal without regard to how to achieve the goal). But OO is still pretty much needed in a ton of cases. So i wouldn't bunch it into the "less used" category. Heck web development benefits greatly from this stuff too! My current webproject is in JSP! yay java!
When you use the tools of OOP separately, you start to appreciate how little you actually need them. A program in a functional programming language will use very little mutation. Polymorphism is a little more common, but not by much. Inheritance is practically never useful - I've only seen one case where it's ever been used outside a OOP language. I have yet to find a case where I'd need all three tools simultaneously.
Encapsulation is also something that seems to have far more disadvantages than advantages. It sounds like a nice idea, hiding your data structures behind an API that doesn't need to change, except in practice it doesn't save much refactoring, and you lose all the benefits with working with data.
Polymorphism lets your database storage object present the same interface as your file storage object. Pretty useful if you want to be able to substitute them!
Encapsulation lets you make sure at compile-time that you haven't accessed anything specific to a particular implementation. If someone else maintains that part of the system, it also lets them mark interface parts that won't change between versions and some implementation parts that may change between versions.
Implicit state mutation lets you open the file (or create the file or establish the database connection pool) on the first attempt to access, letting multiple implementations present the same interface even when different things are going on in the background.
Inheritance is useful if you have multiple objects - maybe you have one for reading inputs, one for storing work-in-progress, one for writing outputs - and you want to reduce code duplication by sharing implementation details. (IMHO this is one of the less useful ones)
TLDR: Use it to unit test your database access.
To be more specific in my criticisms, it's not that polymorphism or event inheritance aren't useful tools. It's more that OOP inextricably ties these concepts together, making it hard to reason about them separately.
Your comment demonstrates this, I think. All the functionality you describe would be implemented in a functional language with polymorphism and higher-order functions, but because an OOP language binds these concepts so tightly together, it's hard to distinguish between them when thinking about a OO design.
Encapsulation is a mechanism to hide information, to conceal internal state or values. I'd argue that this an anti-pattern. Hiding data is almost always the wrong thing to do.
In terms of what you gain, encapsulation might save time, as in some circumstances you can keep the same API without changing the underlying representation of data.
But the price you pay is that you need to reimplement some subset of the functionality a data structure already has, every time you write a new class. You might need to write accessors, iteration, transversal, searches, serialisation, merging, and a whole bunch of other things you get for free with a data structure. Encapsulation means continually re-implementing the wheel, which takes time.
Another huge problem with encapsulation is that you lose transparency and constraints. If I have a system represented fully or in part by a data structure, it gives me visibility and certain guarantees. For example, if I set a key in a map to a value, I know that when I read that key I'll get the same value out. You have no such guarantees with objects.
Encapsulation trades possible gains for certain losses. This might be acceptable, if you had some reason to believe you stood to gain a lot more than you'd lose. But there's no empirical evidence to suggest that there are any significant gains in practice from encapsulation. However you look at it, it seems a really bad trade.
Purely anecdotally, my own experience is that idiomatic OOP design requires an order of magnitude more refactoring than data-driven design.
Talking about 'certain this' and 'possible that' is subjective. I'd have labeled those the opposite way, for instance.
If you value transparency (your 'data structure' is actually an object itself e.g. a hash map) then inheirit. Its not rocket science. One solution doesn't have to fit everything.
Refactoring is a symptom of screwing up the architecture of your application. Excessive refactoring is caused by excessively screwing up. I'd argue that if refactoring seems like a fact of life with OOP, that might indicate there's something very wrong with that paradigm.
> Encapsulation makes it trivial to identify all places that need to be addressed.
If encapsulation was all you needed, there wouldn't be so many refactoring tools for OOP languages that rename and move methods and classes around.
> Talking about 'certain this' and 'possible that' is subjective.
I'm not being subjective. In virtually every OOP application there will be an object that implements at least part of the functionality of a map. At the bare minimum, there will be at least one object that has a getter or a setter method.
>If you value transparency then inheirit.
Inheritance doesn't provide transparency in any meaningful way. The private members of the class are still private. The getters and setters are still opaque.
>your 'data structure' is actually an object itself e.g. a hash map
Data structures are only objects in object-orientated languages. In other systems, they're either primitives or constructed from primitives. At the lowest level, you can construct any data structure you like from an ordered array of bytes.
Its a fantasy that code can somehow be built to last forever.
I'd argue that OOP, particularly OOP involving mutable state, exacerbates the problem immensely. It's extremely difficult to build robust systems in languages that have few constraints and little emphasis on isolating functionality.
Well,
I think one should say the thing to keep in mind with this argument is...
And "certain abstractions are more useful than others" should be certain abstractions should be used more often than others ... but you also still need to know how and when to use ... the less commonly needed ones, 'cause if you don't, they can still bite you.
This seems like the opposite of how it generally works. Classes tie behaviors to data. This is what people generally seem to mean when they talk about encapsulation in OO — the behavior and the data are bound together very well.
For example this pseudoclass
public class Sum1
{
private int _a, _b;
public Sum1(int a, b)
{
_a = a;
_b = b;
}
public int ReturnResult()
{
return _a+_b;
}
}And this other pseudoclass
public class Sum2
{
private int _tot;
public Sum2(int a, b)
{
_tot = a+b;
}
public int ReturnResult()
{
return _tot;
}
}
Have the same behavior/functionality but depend on different internal data - in this sense the data has been decoupled from the functionality: one can treat the class as a black box - the coupling happens in the implementation of the class, but not anymore in the design of it.Why shouldn't an object contain mutable state? When solving a problem for which pure, stateless programming is not suitable, where would you put state if not inside an object?
Refactoring to Functional–Why Class?
This is a multi-part series on Refactoring to Functional Programming
That said, this paradigm is easily broken by bad code.
If you want to make an example of something, then use a Reader, such that you are abstracting away the "source" of what is read and the side-effects thereof. Or an expiring cache (which is a good example of mutable state.) Or a mixed Reader which "reads" from either a cache or in the case of passing the expiration mark on the "key," some unknown "source."
Encapsulation means that objects should perform operations on their data, instead of giving their data to other objects. See Tell, Don't Ask (http://pragprog.com/articles/tell-dont-ask) for details. Encapsulation also lends itself to the Open-Closed Principle whereby class behaviours can be changed through inheritance alone.
Please see (and critique) my self-encapsulation presentation for details:
Not all code has to be applicable to more than one use case. What you're suggesting is premature generalization, which is just as bad as premature optimization. One might argue that p.g. is a kind of p.o. with the metric to be optimized being abstraction.
He just means to show that OO lets us have the luxury of just caring about the functions we need to use to manipulate/use/access the data, without any regard to how it is internally stored.
C# used to be all about OO, then it got FP (lambdas), and dynamism..
The extreme example could be Lisp, in which you can do pretty much any of the paradigms you mentioned.
By tying them together? That isn't what decouple means.
I have to ask, have you ever tried any sort of declarative programming? The fact that you list it, and the two main branches of it separately makes me think you haven't. You should really try it sometime, you might re-think the vague dismissal of all programming paradigms as equals.
This abstraction works well with classical desktop apps (lots of code, one big heap, pointers are always valid), but breaks down badly when your program is about communicating data and you start to cross memory address barriers.
A lot of modern apps are about data. You see a lot of networked apps, db apps and layered apps with different technologies in every layer, communicating with each other only through shared data formats. Such an app is primarily concerned with shuffling data around, and oo breaks down into a horrible mess. Each transition to a data representation requires a complete serialization of the object graph to a reasonable data representation and back again at the other side. This means that you essentially have twice the amount of work than if you would operate on the data directly as you would do with FP.
Once the amount of "internal juggling" with the data exceeds a certain limit, OO might be beneficial. But for data-centric apps, forget it.
Why would you want to do this?
If your data structures don't exist outside of your functional code acting on them, it's hard to reason about the data structures themselves in a vacuum.
It seems to me that structs and/or objects do that pretty well. I'm not sure what you're talking about with 'opaque object structure'. class MyClass { member1, member2 } seems pretty transparent to me.
Anyways, I was just explaining why many people prefer to have struct/object definitions separated from the code that operates on them. YMMV, you don't have to agree.
I'd suggest that a better solution would be to just use maps, at least in languages with good support for raw data structures.
That's exactly what I'm arguing against in my comment on making your important structs/objects and their relationships explicit. Randomly mutating them together all over your program might seem more flexible but at a cost of making you worry about your code rather than your data definitions. And that's without even getting into performance implications.
If you actually need a Map, of course, that's a different situation than the ones I'm thinking.
So you would look at your object structure and could treat it as data, but internally some objects could be proxies to backend system and fetch data on-demand. Some data fields might also be calculated from other fields. This is the idea which Java promotes by having the JavaBean standard. You never know if your data element is backed by actual data or is the result of a computation.
This type of abstraction can simplify certain problems by giving the illusion of a simple data structure, whereas a lot of computations are taking place behind the scene when the data is traversed.
This abstraction is used in may ORM frameworks for instance. You can follow relations between entities and these will be lazily loaded behind the scene as you move around in the object graph.
The problem is that such a living object can only live in its own environment. For ORMs, you cannot move outside the current DB transaction, or else the objects "die". To see some of these problems in the Java world, google "LazyInitializationException".
Pure data, on the other hand, is "dead by definition" so to speak. It does not contain any own logic and can be moved between environments without any problem. The backside of pure data is the very fact that it is dead, that is that you often have to accompany it with logic to interpret it.
With live objects, the interpreting logic is intertwined with the data. This is both the advantage and flaw of OO.
With OO, you have data and logic close together, and have to pay the price if you try to pry them apart.
With FP, you have the data separately, and have to cope with the mental load of knowing which logic you need to apply where in your data structures in order to interpret them.
In fact, most of my experience with large codebases has been in web development, in which you're basically providing a nice front end to a database.
If databases are just structured data, then it seems a bit redundant to wrap that in an object-metaphor (e.g., with an ORM) and then use even more objects to perform operations on the data by way of those ORM-objects.
Django is a good example of the kind of thing I'm talking about. I've been thinking a fair bit lately about the limitations of this style of framework, and I wonder if this idea of functions operating on structured data might be a better way to approach things.
It sounds like Scala might be a good language to experiment with this kind of approach, as others have suggested elsewhere in this thread.
You can still write functional code in OO. Heck if it makes you feel better, you can just make a macro to rename 'namespace' to 'class' and then you can write code like
namespace Utils {
function thingy() {...}
}
Namespaces are generally an improvement over globally defined functions as it lets you mix and match libraries without having to worry that you included the right header files, etc. Again, pragmatism.Having just a generic type gives the language some useful simplicity as the single 'class' container can fulfill all of those needs yet not need the user to remember all the caveats of each specific type as the 'class' concept is generic enough to fit to almost anything.
Having specific types is very good for teaching the different concepts at a higher level as well as documenting what is intended for future readers of the code (as long as they also understand all of the concepts involved). Convention over configuration, really.
I personally prefer the more generic types as they don't try to lock you in to the authors specific biases and requirements - that's what frameworks are for.
When you have Roles, you can build a class with Roles. like lego. Then you can have specific roles and build a class with Roles.
If your OO doesnt support Classes, Roles, Types and method modifieds and functional programming, its outdated.
Seems like your outdated OO needs a metaclass system, up-to-date like Moose from perl.
I think this progress has to do with "type systems" and additionally with the very powerful tools c++ f.e. added to the tool box. The more powerful the toolbox the harder it is to truly grasp it, it seams which steepens the learning curve considerably unless only the very rudimentary "features" of oop are used, as it happens mostly in commercial 9-5 software development.
Imo forcing classes in a non-oop paradigm is just clumsy and, well, unnecessary. When you have a hammer... etc etc
But what if namespaces were values that you could pass around? What if a namespace could be abstract, much like an interface, defining abstract functions and even abstract types? What if you could override the "import" statements a particular module uses?
> no need for classes if you don't need oop
It really depends on what you mean when you say "classes". When I think of classes, I think of subtyping, as in, if type B is a subtype of type A (B <: A), then it means a value of type B can be used in any expression that demands a value of type A (i.e. the substitution rule).
SML has a pretty cool module system that allows for what I say above. But SML modules are special. The cool thing about OOP, when implemented right, is that you don't need special language semantics for special things, as every value can be some sort of object and every type or module can be some sort of class. You know, in a turtles all the way down kind of thing.
See this presentation about the Cake pattern, in Scala: https://www.youtube.com/watch?v=yLbdw06tKPQ
> Namespaces in Java, C++, C#, or whatever else is in this family, are simply too dumb. Their sole purpose is to avoid name clashes.
That statement is just completely ridiculous. Classes are for inheritance, abstraction and polymorphism. You're saying you think of classes as inheritance and polymorphism without encapsulation, but encapsulation is the key trait for decoupling.
It's been awhile since I worked with SML, but if I recall, the modules you say are cool and special, are cool and special because they give you the three important traits of OOP.
I don't know whatever gave you that idea, but it's quite the opposite, unless we have completely different definitions for what encapsulation is.
Abstraction is the key trait for decoupling, not encapsulation. Encapsulation couples behaviour and state together.
I see where you're coming from though, and I think decoupling is a combination of abstraction and encapsulation, not one or the other exclusively.
If one class is free to use the internals of another then it is not a sound abstraction by definition.
I see where you're coming from though, and I think decoupling is a combination of abstraction and encapsulation, not one or the other exclusively.
Your view of abstraction is too limited. Abstraction need not involve classes or objects at all. Abstractions may also be built with modules/namespaces, parametric polymorphism (aka generics) and other forms of ad-hoc polymorphism (such as type classes). All that is required to achieve abstraction is a function or data type which hides its implementation details in a way that allows it to be interchanged freely with other functions or data types that match its interface. Encapsulation is only one way to achieve such hiding.
> If one class is free to use the internals of another then it is not a sound abstraction by definition.
So abstraction is not sound without encapsulation.
I guess the definitions of FP and OO are fuzzy enough that someone will probably come and tell me why this isn't a true Functional architecture, but so far I haven't seen anything close though to a consensus on what the strict requirements of FP really are such that it would preclude any form of binding data and methods. Specific languages are one thing, but when talking about programming paradigms in general I see them as forming a hugely overlapping Venn diagram.
Ok, so I don't do that with controllers for obvious reasons, but my business logic and utilities I try to.
Nor unit tests I assume
A few thoughts on the subject: http://misko.hevery.com/2008/12/15/static-methods-are-death-...
If you use static classes for business logic, you typically end up with a tightly coupled system in which managing class dependencies is a pain.
I think that "messing around with interfaces all the time" is worth the fuss in the long run.
The dialogue of the article is entirely about coupling, and in OOP figuring out how to make a loosely coupled system is what separates the grand masters from the beginners. Designing a loosely coupled system is incredibly hard and requires years of deliberate practice to master. So when someone who's a beginner or not very good at OO design claims OO isn't a valuable paradigm, I don't listen. Bad OO can be less valuable than no OO, just like anything else, and just like anything else, that doesn't make the whole paradigm bad.
I've explored functional programming in a couple of college courses now, and find it very intriguing. When it's time to go a make a system, however, I find it difficult to boil down functional principles into the system I want. This is a complaint in the same vein as the OO complaints. Functional programming is incredibly impressive when designing a behavior, but what separates the masters from the beginners seems to be when it's time to model an entire system. This is the current separation in my mind: OO is designed and really good for modeling a complex system that involves lots of mutation, and functional programming is really good for modeling and separating behavior within a system.
I don't think we have grounds to say one is better than the other yet. Both OO and Functional have their niches where they're amazingly effective, and both have a giant gray area where it's difficult to mold the pure paradigm onto a solution.
I think the best solution so far is a mixture of the two, such as we see in Scala. Though, a mixture too has its own set of drawbacks. Mainly what seems to be an explosion of language complexity and a giant need for design conventions and limitations when there are so many possible routes to a solution.
The best of the current climate is a mixture of the two, with a framework that clearly defines and separates where and when to use one paradigm over the other, so you aren't bogged down with the additional complexity.
Is there an equivalent for programming? Github and Stackoverflow are good resources, but it would be interesting to see something more structured. Perhaps a DB of a fixed set of problems such as projecteuler.net with voting and analysis of the submitted solutions.
I'd argue that this is where OOP struggles the most. Because mutation in OOP is implicit and unconstrained, it's more difficult to manage than in FP languages, which typically have more sophisticated controls and constraints for handling state.
http://www.cs.ox.ac.uk/ralf.hinze/WG2.8/31/slides/martin.pdf
PS: C makes me feel like this too! I just know how the pieces work.
Classes are a tool you can use to design a solution to your particular programming problem. Sometimes the problem with call for a few large classes. Sometimes it will call for an evenly balanced network of small classes. Sometimes there will be a lot of DTOs, and sometime none. Sometimes large classes will cause maintenance problems because there is a lot of complexity confusingly jammed in one place, and other times they will be a boon because you don't have to look in lots of confusingly named files to discover what you are looking for.
Criticizing a design by how well it conforms to abstract rules, rather than criticizing its fit to the actual problem will often lead to confusion.
These rules of thumb are useful, but only as a way to question whether your design is a good fit - I.e. "Would it be better if this class had more behavior or less behavior? Would it be better to split this class into smaller components, or should this group of similar classes be coalesced into a single entity?"
I've seen some nice slides from Clojure talks that talk about how many OO abstractions are complected (combined) versions of simpler abstractions. If anyone has seen the slides I'm talking about, please share. For example, a class is combination of a namespace and ___. Possible answers include mutable state, shared data, and so on.
I think one of his most important points is that objects are good for representing, well, actual objects. As in, you have a mouse, or screen or some little robot that you are controlling through code. And that's all they are good for.
Need a way to define a bunch of static methods and avoid name collisions? - you want a namespace.
Need a place to store a bunch of data about something? - you want a associative array.
Need a way to call the same function on different types? - you want an interface.
I'm not sure about this, but I suspect part of the problem stems from the fact that object-oriented languages (usually Java these days) are the first language that students are exposed to. Once you start thinking in OO abstractions, it takes some effort to break out of the mindset.
To enforce an invariant but of course. Just ask Bjarne.
I believe this distinction is a critical one because an application with a lot of shared state is more difficult to scale than one without. As another poster pointed out, in a shared addressed space such as a desktop app, this isn't a concern. But if you want to scale an application across multiple address spaces, communicating and synchronizing the state of objects between these spaces tends to be difficult.
So, my tendency is:
Small and shared address space? Tend to use OO patterns and implementations.
Big and distributed address space? Tend to use FP patterns and implementations.
Note, I don't consider OO vs. FP a language choice – I consider it a programming paradigm choice.
That gap is very brittle. Nightly batch windows become too short. Users expect real time updates leading to major redesigns of entire systems, like Google dropping MapReduce for their search index.
But I think your point about state being the major difference between OO and FP is absolutely true. In OO systems, statefulness is the default everywhere. Nothing is formally known about state in OO system and that is a bad thing. We need state to be explicit and formally specified.
Do put your object in classes, but don't put behaviors there. Use classes to allow static type checking so that functions taking them can guarantee certain field exist.
Separate behaviors out into its own module. I'd avoid calling them classes here because there will be confusion. Interactions between objects can be implemented in FP style. This is where you get to use map and reduce.
I've been learning about DCI (data context interaction) recently. I can't say I've fully grasped it yet, but it did opened my mind on how to do design differently.
You seem to be pretty emotionally invested in FP vs any other programming paradigm. I'm more of a "lots of tools in the box" kind of guy.
Alan Kay's summary is interesting: http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay...
I also wouldn't say I'm particularly emotionally invested in FP, just that I'm very skeptical of OOP as a paradigm. OOP languages tend to promote hidden, mutable state, but visible, immutable values are far more useful.
Its exists on decent languages. Which in case allow OO also.
ie. perl, allows all that, and has Moose which allows Class and Roles and Types. So you can build classes like lego, literally.
That's a common misconception. First-class functions and higher-order functions are definitely commonly used in functional programming, but they are not what makes it functional programming. As with any paradigm, there is no universally agreed-upon definition, but most functional programmers will likely agree that lack of mutable state and lack of side effects are much more central to functional programming than first-class and higher-order functions. The latter are really just useful and elegant tools to help accomplish the former.
Not true.
> Pure functional languages make side effects explicit, but it isn't about them being missing.
True. I should have been more clear about that.
I.e.,
(display "hello world")
returns whatever it returns (we throw it away), but also puts that string on the monitor. The latter action is not just computing a function (in the sense of FP) of the inputs.For more, see http://www.eecs.berkeley.edu/~bh/ssch20/io.html (search for "side effect").
The more specific claim that you need side effects for a program to do anything is also false. You can prove mathematical theorems with programs that have no side effects. Of course now you'll say that that only works because of the compiler, which does have side effects, but that's really just moving the target so you can be "right" (as you did with this post).
Even if theorem proving isn't good enough, since the entire purpose for having the term "side effects" is to be able to usefully discuss referential transparency, the other poster who noted that IO can be an effect and not necessarily a side effect was correct. If IO is isolated, it is not a side effect, it is just an effect. A good example of this is the execution of the main action in a Haskell program.
>You can prove mathematical theorems with programs that have no side effects
No, of course you can not. How do you see the result? That requires a side effect of some kind.
>A good example of this is the execution of the main action in a Haskell program.
That is a terrible example, as executing main precisely is a side effect.
The result is whether or not the program type-checks.
Your original claim was, again, that "without side effects you can't do anything". So, again, unless you are claiming that functions and libraries "don't do anything", your original claim was incorrect. Your new claim, that programs must have side effects to do anything, is still wrong but more debatable.
You can call me obtuse if you want to, or you can learn how to communicate clearly and say what you actually mean. Doesn't much matter to me either way.
Ok, you are very confused. Type checking has nothing to do with program execution. Type checking is done at compile time. Any program with no side effects, the compile can safely optimize into nothing, since it does nothing. The compiler does the type checking, not the program.
>Your new claim, that programs must have side effects to do anything, is still wrong but more debatable.
It is the claim I made and you replied to. If you want to be pedantic and obtuse you can't expect people to not call you out on it.
> Ok, you are very confused.
You are both very arrogant and wrong. Not a pretty combination. Thank you oh so much for telling me that type checking is done at compile time, as though there were the slightest possibility I didn't know that given what I've been saying.
If you took some time to learn how to have a conversation on the internet without being an asshole, you might actually learn something. Until then, I'll stop wasting my time trying to have a discussion with you. Cheers.
Why not just use algebraic data types and modules? Classes are such a verbose, jumbled, complected mess compared to those simpler tools.
Sorry, I not familiar with that term. Can you explain that more?
I would hazard to guess that functional programming or any other solution will go through the same type of evolution and we will be looking back in 10 years at how immaturely we used the technology. Then we will circle back to yet some other technology that was previously used and went out of style, with some new insights added.
It seems to me that we go in a great big circle over and over again, picking up a little bit of new info each time around.
On a larger scale paradigms usually pick a spot along the verbosity continuum. Concise and information dense or verbose and information free? This is another eternal cycle. Some modern java looks about the same as 1960s COBOL to me.
https://www.destroyallsoftware.com/talks/boundaries
A lot of people I know consider object-oriented design orthogonal to the programming style — that the real improvement is moving from a procedural to functional approach. Any system that grows large enough to clearly define an architecture technically is object oriented, so long as it's passing messages among stable interfaces.
You want to have that functional core and imperative shell. Tell above, ask below.
It's just unfortunate that a lot of "object-oriented programming" that you learn in school is really just imperative programming with interfaces ;)
@straws: I'm curious, why do you think that the situation you mention above implies that such a system is 'technically' object oriented?
If I'm understanding your claim, I disagree. All you need are mechanisms for:
(1) function-calling or message-passing (I don't think you were trying to emphasize an extremely rigourous definition of 'message passing' were you?)
(2) namespacing
(3) validating a 'stable interface'
There are many definitions of OO, but this is one is good enough for my point: "Objects, which are usually instances of classes, are used to interact with one another to design applications and computer programs" (from http://en.wikipedia.org/wiki/Object-oriented_programming)
You don't need object-based inheritance (e.g. Java) or prototype-based inheritance (e.g. Javascript) to build large systems in this way.
For example, you can build very large systems in Erlang (passing messages too!) without any kind of OO.
There are lots of examples of how functional languages can enforce interfaces without classes, including Haskell.
It's unnecessary to create classes for functionality when it's unnecessary to create objects for functionality. Here's an eloquent article on that subject:
http://me.veekun.com/blog/2013/03/03/the-controller-pattern-...
And then you can build a class like LEGO, literally.
Because, it has Class and Roles, a class can extend another class. And a Role can be built with multiple roles. And a class can be built with multiples Roles.
Your OO is outdated if it doesnt implement classes, roles, types and at least method modifiers.
And your language should allow first function class to allow functional programming if you desire.
Perl has all that and comes installed in any unix/linux/mac.. try in your terminal: $ perl -v
Every linux/unix/mac system runs perl. So your company is probably using perl and they dont even know.
Ultimately, classes are about code organization and reuse. Done properly, it leads to a well maintained program. Functional programming...it still needs to be organized somehow, whether you put them in classes or namespaces, the last thing you want is spaghetti code. Now depending in the type of programming, you may need to preserve state, which can be quite challenging in a purely functional environment.
What makes you say that?
Another observation is that it's far easier to read someone else's code if there is no mutation. For eg. I have enrolled for the proglang course[1] on coursera and only yesterday I completed this weeks homework which involves enhancing an already written game of Tetris in Ruby. Major part of the assignment was about reading and understanding the provided code that uses OOP and makes heavy use of mutation. It was quite difficult to understand what one method does without having a picture of the current state of the object, specially with side effecting methods that call other side effecting methods. A few times I had to add print statements here and there to actually understand which one is being when and how many times. While I could score full marks in the end, I am still not confident about completely understanding the code and have a feeling that if I ever need to work with it again, the amount of time it will take to load up everything again into my mind's memory will be equal to what it took for the first time.
Of course, one could only make a true comparison by studying an implementation of Tetris written in FP style. But from my experience with reading and writing code in Erlang (for production) and Racket, Clojure (as hobby) I find it relatively easier to study functional code written by others.
That's one of the benefits of OOP: it forces you to think harder about where things belong, and this really helps as codebases grow. A "utils" class is often a sign that things could be better organized.
Another aspect of this is unnecessary effort expended on deciding if A.operateson(B) or B.operateson(A). Sometimes, you want to Operate(A, B). If your language doesn't allow that, you end up with operator.Operate(A, B).
Classes are not always the best organizational tool.
I'm interested in this concept, but I'm not sure how to go about applying it to my own work as a front-end web developer. Most of the resources online are theoretical.
Beyond that, Michael Fogus — big in the Clojure + Clojurescript community — has Functional Javascript which explores functional concepts using Underscore: http://www.amazon.com/Functional-JavaScript-Introducing-Prog...
Marijn Haverbeke — a big Lisp hacker and the creator of Codemirror — has a nice chapter in (the free!) Eloquent Javascript as well: http://eloquentjavascript.net/chapter6.html
You should also check out how Javascript supports functional programming in languages that compile to Javascript such as LiveScript or Elm.
Christian Johansen - Pure, functional JavaScript http://vimeo.com/43382919
Both have merit depending on the skill-set and staff available to you, scale of project and existing infrastructure.
I was however very disappointed when the author bundled interfaces into the mix as if it was the same as the rest of it. The interface enables you to support many different types of behaviour and enables you to structure your libraries in different ways. It's a different aspect from just classes themselves.
Genuinely I don't think shit like this is healthy. Smacks of religion.
The core argument is more of philosophical in nature in terms of paradigms, because from functional programming view a function just acts on a data transforming it to other form. But in pure OO world (like Java) one can not dare to think beyond objects so for them it has to be in a object.
I don't know if I am understanding it correctly but one of the reasons I absolutely loved Backbone.js was that it kept state of our DOM. Is this relevant to above discussion? because state surely looks pretty beneficial.
I'm not trying to hate on JS either, I think it was a bit of a small miracle what Brendan Eich pulled off under the constraints he had and I'm thankful for JS every day. However I think it's fair to say that something like Ruby's metaclass and mixin system gives you 99% of the modeling power of advanced prototypal modeling with 99% less confusion. Obviously there are ways it could be done better and more explicitly than in Javascript's typeless object world, but even then I don't see where the win is. We need better ways to manage state and mutation in mainstream languages, not more ways to compose objects.
I'm seeing where this is going: GoLang.
But also the old question of where to put a method seems like unecessary mental overhead for solving a problem. Use modules and just pass things in. You could probably even put some syntactic sugar in the language so that you could use the "object".method notation on the first argument passed in if you really wanted to.
So someone give me clojure with optional typing, a Python-like syntax, and get off my lawn!
some language designers see and fully appreciate the benefits of both. They start putting class synonymous structures in FP languages or FP functionality in OOP languages. This is the future of the mainstream (Ex: EcmaScript 6 has classes/types, C# has Linq, closures, lambdas ETC).
http://www.theguardian.com/commentisfree/2013/nov/16/left-ri...