Earlier quoted context omitted.
Make Dog implement Healable, duh.
The original author can do that. Another author cannot add that functionality later, as a library. The can only define a new kind of dog.
In defense of complicated programming languages
281–290 of 379 posts
Re: In defense of complicated programming languages
#282Earlier quoted context omitted.
Using C, which doesn't even have closures, as an example of why this doesn't work is rather silly. How can you have closure-based classes without closures? The ergonomics are beyond horrific in this case but I don't see how that's relevant. > And yet, there are approximately 0 examples of the "closure-backed classes" example you give, while every vaguely popular language except C has some variant of polymorphic class…
A class is any construct that can: - expose multiple function (implementations) as a single unit - be chosen at runtime as a representation of a contract (polymorphism) - (optionally) encapsulate some state accessible only to the functions of the class This construct comes up naturally in a wide variety of programming tasks, mainly related to the large-scale organization of code. Here are some examples of language co…
struct MyObj {
vtable: MyInterface*
data: void*
}
Which is how dynamic traits are implemented in Rust. The C++ approach of a pointer to: struct Obj {
vtable: ...
field1: T1
field2: T2
field3: T3
}
Pretty much means you need to define all the interfaces you implemente on class declaration, which is not nearly as nice as doing it independently (as with traits, protocols, typeclasses, go interfaces, etc.)My point is that MyInterface is just a vtable, a class is a function that fills in that vtable, an object is a pair of a filled in vtable and data. These mechanism are restricted to the compiler for no good reason, which is why you end up with "metaclasses" and "mixins" and all that other nonsense. Just expose the mechanism itself and give it some nice syntax.
Classes mix too much stuff together: inheritance, subtyping, access control, data specifications, interface specifications, etc. We've figured out that's not really a good thing which is why Go and Rust rightfully split them up and use separate mechanisms.
I'm saying go even further and don't hide the runtime representation, let me create these things at runtime if I so wish. That gives metaclasses and mixins and what not for free (with a constexpr-like mechanism they can even be done at compile time).
You can still keep traits as the way of defining bundles of methods, they're also useful as generic concepts, that goes into the ergonomics of it.
This is a similar discussion to Zig generics. Zig has no idea what generics are, a "generic" is just a function that given a type produces another type. Works pretty well.
> A class is any construct that can:
That's just your definition. Your points describe an abstract datatype, a concept that predates classes. We could call that a class these days, but that's not reflective of the programming language construct called "class" as used in language like C++, Java, C# and friends.
Re: In defense of complicated programming languages
#283Earlier quoted context omitted.
Type classes and ML functors are also a way to do polymorphism and dynamic dispatch on data structures. So which languages are left without object systems?
Polymorphism and dynamic dispatch don't equate to an object system in and of themselves. At minimum, I'd say an object system needs some form of messaging and state hiding. That is, an object holds hidden state, and responds to external messages.
I advise some reading "The Art of the Metaobject Protocol", or similar literature.
Re: In defense of complicated programming languages
#284Earlier quoted context omitted.
Polymorphism and dynamic dispatch don't equate to an object system in and of themselves. At minimum, I'd say an object system needs some form of messaging and state hiding. That is, an object holds hidden state, and responds to external messages.
Some would say that starting from lambda calculus it would be enough to reach there. I advise some reading "The Art of the Metaobject Protocol", or similar literature.
Re: In defense of complicated programming languages
#285Earlier quoted context omitted.
Stack unrolling is a complicated process. It's tempting to think of them as a kind of return value, but most languages do not represent them this way. (I believe it's a performance optimization.) Flying to the nearest catch can also be complicated, as it's a block, that involves variable creation, and this possible stack changes. Again it's easier to model as a normal block break and then a jump, but that's not the u…
I always expect them to use (thread-) global state, not unlike good old errno just more structured. There's always at most one bubbling up so that's how I would do it.
Instead, compilers use long jumps and manually edit the stack. I'm not sure it makes a lot of difference today, but branches were really problematic by the time the OOP languages were popularizing.
Re: In defense of complicated programming languages
#286Earlier quoted context omitted.
> the compiler doesn't let me have two mutable references to that struct even if one of them only changes X and the other one Y. The semantics of mutable references and other interface constructs must be independent from actual implementation, to allow for changes in the latter. So Rust is behaving as expected here. If the changes to X and Y are truly independent, you can have a function that returns separate mutable…
> then the changes are no longer truly independent. But the author of the code is telling you that they are independent. The author may be proved wrong if some future change accidentally triggers dependence but we as humans can have knowledge that the compiler can not have. The compiler sees a possibility of conflict and wants to protect you from yourself. That is a usability issue.
Re: In defense of complicated programming languages
#287Earlier quoted context omitted.
> A language with a short learning curve is like a toolbox that’s nearly empty. You quickly run out of ways it could help you. Very quotable! That's why I like it when languages allow you to start writing simple code and gradually make it more complex. Haskell for example is not like that. Python does better here. I think Scala is one of the best languages in that regard.
> Haskell for example is not like that. Python does better here. I think Scala is one of the best languages in that regard. This seems ripe for getting a lot of passionate anecdotes out of the woodwork.
Re: In defense of complicated programming languages
#288Earlier quoted context omitted.
Just a quick word about polish notation: The only reason why humans seem to prefer infix notation, is because it is what's being taught in school. The first mathematical expressions most people get to see is 1 + 1 There is no reason why someone who was introduced to + 1 1 at an early age would find it less "natural" than infix. I think the only reason why infix is the dominant notation is historical: Prefix notation…
White space is bad for readability anyways. I don't think that would be doable.
Re: In defense of complicated programming languages
#289Earlier quoted context omitted.
> unfamiliar gets conflated with unintuitive and hard all the time In a deep sense unfamiliar and unintuitive/hard can be viewed as the same thing (see e.g. the invariance theorem for Kolgomorov Complexity). Hence striving to be "familiar" is still a virtue that it makes sense for a programming language to aspire to (balanced of course against other concerns).
Familiarity is a characteristic of the agent. Intuitiveness/duficult is of the object.
Or as Von Neumann said about mathematics (and I think the same is applicable to CS and programming): "You don't understand things. You just get used to them."
Re: In defense of complicated programming languages
#290Earlier quoted context omitted.
I understand this thought process, but in my opinion it's the wrong way to think about software concepts. Understanding what a bridge is doesn't mean knowing how to build one, and in fact tying your understanding to a certain implementation of a bridge just limits your ideas about what is, in fact, an abstract concept. We understood functions as "mappings" between objects for hundreds of years, and when programming c…
I didn't understand how engines worked until I took them apart, either. I was taking things apart to understand them long before computers :-) But the notions of sending a "message" to a "method" just was way way too handwavy for me. I like examining the theory after I learn the nuts and bolts. > Understanding what a bridge is doesn't mean knowing how to build one If you don't know how to build one, you don't underst…
You mean to an “object”?
Also, this looks like a perfect example of theory vs practice, having different implementations of object communication as in classic OOP vs actors etc?