CLOS itself is great, however the decoupling of data and methods is something at times I find leads to harder to understand code.
I think that might be familiarity rather than anything fundamental. I often find the coupling of data and methods to lead to harder to understand code; if I want to define a new method on an object in Java, I have to either subclass it or modify the class itself. Even if the method is ancillary to the core functionality of the class. That seems strange to me.
> I want to define a new method on an object in Java, I have to either subclass it or modify the class itself.
maybe what you are looking for is extension methods?objective-c/swift/kotlin/c# all support them to varying degrees (but sadly not java afaik)
A quick read of the wikipedia article makes it look like in C# you can do this, but not in Ruby.
That said, I mostly work on CL code by myself, maybe CLOS is more useful to large teams, maybe that's where it really shines and why people praise it.
I don’t know about that. To me, interfaces is the best thing after sliced bread, “OOP” or not. In particular, they bring some sanity to the design in the modern C++, where you would use templates in the lower level parts of the application, for performance, and interfaces at the higher level, for sanity.
You don't get much more small and focused than at the function level. God objects and god interfaces are a much easier trap to fall into in a OOD paradigm like Java et all.
The Javas and C#s of the world were designed with 1990s OOP in mind. Ironically they're among the hardest languages to do good modern OOD in.
HN's really starting to put me off with suchlike rife blanket-damning posts that are uninformative and usually come from people who have little experience.
You wouldn't go into why JavaScript is bad to point out that you don't need to write JavaScript to make a web page. You would just note that JavaScript was a late addition to the web and wasn't the first language usable on it.
Plenty of people were writing CL before CLOS existed.
You opined in addition on the quality of clos. That could have been very useful if you'd explained it.
This account is 52 days old, but the user behind this has been reading and posting on HN for a bit longer (let's say since PG decided to put HN online).
For the other comment, my point is that "genuinely wise" is much rarer nowadays, and instead we're drowning in "genuinely clueless". This is why you shouldn't learn about something's worth by reading HN comments nowadays. Instead you can put a limited amount of time actually studying the subject and then decide if it's worthy of more of your time or not.
I get further pissed off by having people argue back when I say something from my small island of expertise (SQL and a few other things) they clearly know less than me - I can't learn from them and they won't learn from me. I don't mind n00bs, we all were once, but to willingly remain n00bs by rejecting information, well I can't comprehend it.
I miss posts from the likes of BeeOnRope. The really good people get driven away.
But I agree about general data structures. Some of the sequence functions are generic but not enough of them. I presume this happened because circa 1990 generic dispatch was too slow to handle high speed data traversal. That's no longer true, and many libraries exist to "generify" more of Common Lisp.
* 123
123
That looks good, let's see... * (describe *)
123
[fixnum]
Huh? What's a FIXNUM? * (describe 'fixnum)
COMMON-LISP:FIXNUM
[symbol]
FIXNUM names the built-in-class #<BUILT-IN-CLASS COMMON-LISP:FIXNUM>:
Class precedence-list: FIXNUM, INTEGER, RATIONAL, REAL, NUMBER, T
Direct superclasses: INTEGER
No subclasses.
Sealed.
No direct slots.
Uh-oh.Anyway, you see what I mean now by not being able to use Common Lisp without the CLOS. Unless by using the CLOS you mean having to explicitly opt-in by using classes, multiple dispatch, multiple inheritance, generic functions, the MOP and all that weird stuff.
Yes, that's what I meant. The fact that the CL type system maps into the class system doesn't mean we all code OOP. If you want to argue semantics, sure..
SBCL will generate _very_ different code for fixnums vs general objects, so much so that claiming that (+ 1 2) is using CLOS makes no sense.
CLOS is an object-system construction kit as much as it is an object system. I generally like to solve problems by building a language in which the solution is simple and straightforward to express, and CLOS provides handy tools for defining data structures and suites of operations on them that facilitate that approach.
I also like to work by livecoding, and that sometimes means redefining types that have live instances. If my types are CLOS classes, the Lisp will automatically catch changed definitions and will update existing instances to conform to the new definition. That's awfully helpful in a livecoding context.
CLOS has also come in handy when I needed to build novel systems of data types and function dispatch. For example, Ive worked on several knowledge-representation systems over the years, and it's been useful to have CLOS features for constructing novel inheritance schemes, access controls, truth-maintenance, persistence mechanisms, and so on.
So I've used CLOS quite a bit over the years. Some tools vex me more every time I have to use them. Others are a greater pleasure to work with each time. In my experience, CLOS has been a tool of the second kind.
http://metamodular.com/SICL/call-site-optimization.pdf
(I think a modern version of Common Lisp would take this idea and run with it, making most or all built-in functions generic.)
CLOS really shines when it comes to problems that benefit from method combination, which allows one to decompose computations into reusable nuggets that can be reassembled using multiple inheritance.
I agree with you, though, OOP should be something you reach for purposely, not as a default. And, unfortunately, the waters have been so muddied, that I couldn't tell you the best purposes to reach for it. About the best I can see is that it does lend itself well to metaphor, and people communicate almost exclusively in metaphors, when it comes to programming?
Sure, but recall that CLOS really consists of two distinct components. The class/object system, and generic functions.
Since CLOS is baked into the CL type system, generic functions will happily dispatch against DEFSTRUCT types (as well as all of the other types, not just objects). Add the ability to :include other DEFSTRUCTS, and the idea that when DEFSTRUCT B :includes DEFSTRUCT A, then the type-of of B is both as a B struct and an A struct, then you get back alley inheritance using structures.
So, now (in theory) you get the efficiency of DEFSTRUCT, but all of the dynamic dispatch giddy goodness of DEFMETHOD, when and if you want to use it.
It can be a really nice compromise.
As far as performance goes, it just hasn't been a problem for me, even when doing graphics and image processing. A pattern that's worked really well is to use OOP to structure and organize everything, and then have the implementation details flushed out with functional or imperative code. It's the best of all worlds.
And it's actually a good pattern in most OOP languages because it slows things down in most of them. The vtable in C++, extra GC in Java, object attributes vs. locals in Python, etc. Avoiding objects in performance critical code is just generally a good idea.
Yes I'm aware of the things you get in CL you don't get in Java: multiple inheritance, defmethod works on arbitrary types by default rather than having to create interfaces, better introspection.. but I don't care. If you're using these features so much there's probably something overly complex with your code to need to do so. Or you're working in such a complex domain you need to, in which case go ahead..