Hacker Newsnew | past | comments | ask | show | jobs | submit | LukeShu's commentslogin


libgccjit is much higher level than what's documented in the "GCC Internals" manual.

Inheritance is just the unnecessary coupling of composition and polymorphism.


Even before I got to the point where I decided I didn't like inheritance, I distinctly recall having conversations about how I felt that using inheritance for anything other than polymorphism didn't usually end up with particularly clean code. I can remember a conversation about this at least as far back as the summer after my freshman year of college, and I don't think I was aware of the idea of "composition" yet, because I remember phrasing my point as something like "inheritance shouldn't be used for 'code-sharing', only for polymorphism".


Out of curiosity, when you say you don't like inheritance, does that mean you never use it at all, or you only use it rarely?

Because even though inheritance often is used in a wrong way, there are definitely cases, where it is the clearest pattern in my opinion.

Like graphic libary things. E.g. everything on the screen is a DisplayObject. Simple Textfields and Images inherit directly from DisplayObject. Layoutcontainers inherit from DisplayObjectContainer which inherits from DisplayObject.

Inheritance here makes a lot of sense to me and I don't see how it could be expressed in a different way without loosing that clarity.


> I don't see how it could be expressed in a different way without loosing that clarity.

What value does the inheritance provide here?

Can't you just use a flat interface per usecase without inheritance and it will work simpler with less mental overhead keeping the hierarchy in mind?

Explicitly your graphic library sounds should be fine to have the interface DisplayObject which you can then add default implementations on. (That's a form of composition)


That would be way, way more verbose for everything.

Every display object has a x y width and height for example. And there is basic validating for every object. Now a validate method can be conposited. But variables? Also the validating, there is some base validating every object share (called wih super) and the specific validating (or rendering) is done down in the subclasses.

And even for simple things, you can composite a extra object, but then you cannot do a.x = b.x * 2 anymore, but would have to do a.po.x = b.po.x * 2 etc


> Every display object has a x y width and height for example.

Intuitively¹, I feel like this is something that should be separated out into a BoundingBox object. Every component that needs a bounding box satisfies a small `HasBoundingBox { getBoundingBox(self) -> BoundingBox }` interface. Maybe there's a larger `Resizeable` interface which (given a type that satisfies `HasBoundingBox`) specifies an additional `setBoundingBox(self, bb)` method.

You don't end up with a tidy hierarchy this way, but I'm not sure you'd end up with a tidy hierarchy using inheritance, either. I feel like this sort of UI work leads toward diamond inheritance, mixins, or decorators, all of which complicate inheritance hierarchy. Flat, compositional design pushes you toward smaller interfaces and more explicit implementations, and I like that. The verbosity can be kept in check with good design, and with bad design, the failure mode leans towards more verbosity instead of more complexity.

For more complicated features, composition & interfaces can make things more verbose, but honestly I like that. Inheritance's most powerful feature is open recursion (defined in the linked article), and I find open recursion to be implicit and thorny. If you need that level of power, I'd rather the corresponding structure be explicit, with builders and closures and such.

[1]: Not saying this is correct, but as someone who prefers composition to inheritance, this is what feels natural to me.


"You don't end up with a tidy hierarchy this way, but I'm not sure you'd end up with a tidy hierarchy using inheritance, either."

Well, I am sure, that all the graphic libaries I ever used, had this inheritance model. (The graphics libary I build, as well.)

The libaries I have seen, that used a different model, I did not really like and they were also rather exotic, than in wide use. But I am willing to take a look at better designed succesful inheritance free ones, to see how it can be done,.if you happen to know one ..


None of the graphics libraries you've ever used were built with mixins, decorators, or multiple inheritance? I confess I never went too deep with GUI toolkit programming, but Swing, for instance, definitely uses decorators (e.g. JLayer).

Neither Go nor Rust have inheritance, so any graphic library implemented in those languages will be inheritance-free; ditto anything in a functional language, for the most part. In general, these tend to be very declarative toolkits, being post-React, but they should illustrate the point. For something more widely used in industry, I know Imgui is a popular immediate-mode library.


I mean if you writing joe slop tax softare you can use whatever mixin decorator singleton factory performance be damned, slop doesn't need performance, in fact, is frowned upon in slop developers as too showy and flashy, puts people off.

Now if you're say writing a high performance game, rendering engine, then maybe you want to squeeze out another 10 frames per second (FPS) but not committing resources to the overhead of that mixin decorator singleton factory facade messenger design pattern and just have some concrete tight C or assembly loop at the beating heart of it all


To avoid splitting the discussion by responding directly to your comment above, since I have thoughts about this one as well: I've written Rust professionally since 2019, which doesn't have inheritance, so I don't use it at all. I guess my point is that I don't miss having inheritance as a tool in my everyday coding, and I actively prefer not having it available in Rust.

In terms of what you're saying here, the extra verbosity is not really something that either bothers me or is impossible to work around in the context of Rust at least. The standard library in Rust has a trait called `Deref` that lets you automatically delegate method calls without needing to specify the target (which is more than sufficient unless you're trying to emulate multiple inheritance, and I consider not providing support for anything like that a feature rather than a shortcoming).

If I were extremely bothered by the need do do `a.po.x` in the example you give, I'd be able to write code like this:

    struct Point {
        x: i32,
        y: i32,
    }

    struct ThingWithPoint {
        po: Point,
    }

    impl Deref for ThingWithPoint {
        type Target = Point;

        fn deref(&self) -> &Self::Target {
            &self.po
        }
    }

    fn something(a: &mut ThingWithPoint, b: ThingWithPoint) {
        a.x = b.x * 2;
    }
Does implementing `Deref` require a bit more code than saying something like `ThingWithPoint: Point` as part of the type definition? Yes (although arguably that has as much to do with how Rust defines methods as part of `impl` blocks outside of the type definition, so defining a method that isn't part of a trait would still be a slightly more verbose, and it's not really something that I particularly have an issue with). Do I find that I'm unhappy with needing to be explicit about this sort of thing rather than having the language provide an extremely terse syntax for inheritance? Absolutely not; the extra syntax convenience is just that, a convenience, and in practice I find it's just as likely to make things more confusing if used too often than it is to make things easier to understand. More to the point, there's absolutely no reason that makes sense to me why the convenience of syntax needs to be coupled with a feature that actually changes the semantics of the type where I want that convenience; as comment I originally replied to stated, inheritance tries to address two very different concerns, and I feel pretty strongly that ends up being more trouble than it's worth compared to just having language features that address them separately.


Inheritance is not necessary, but then very few programming constructs are absolutely necessary. The question is does it help program clarity or not. I think that in some cases, used sparingly, it can. The main danger of inheritance is not that it is OO, but that it is not OO enough. It breaks encapsulation by mixing properties and methods between base classes and derived classes without clear boundaries. Composition is safer because it preserves encapsulation. In general, I think that protected abstract methods are a code smell, because they usually indicate close coupling of details that should be kept separate between the base and derived classes. But used correctly, inheritance can be more succinct and convenient.


Delegation is a very useful part of composition. Almost all OOP languages have two techniques to delegate some methods to another object:

- manually write a bunch of forwarding methods and remember to keep them updated, or

- inheritance.


There’s also automatic delegation like in Kotlin: https://kotlinlang.org/docs/delegation.html


To be fair, the compiler generally forces you to keep the forwarding methods updated. It can be irritating, but there's little risk of forgetting in a statically-typed language.

Manual forwarding also operates as a forcing function to write small interfaces and to keep different pieces of logic separated in different layers, both of which feel like good design to me. (Though I'm not saying I'd turn my nose up at a terser notation for method forwarding, haha.)


...yes? Hence me saying that 'composition' and 'polymorphism' have often been unnecessarily coupled together in 'inheritance'?

Compare: Ruby mixins or Go embedded struct fields.


Yes, subscribing to bullshit I don't want them to work on will surely send the signal that they're focusing on the wrong things!


While exact definitions vary, it's a term of art for Research Unix ≤ V7, perhaps plus or minus a version, perhaps including contemporary derivatives.


At the same time, it's easy to believe that MIT of 2013 is very different than MIT of 1988.


While that's entirely possible, MIT was established in 1861. I think the old boys club was established long before 1988.


I’m pretty sure MIT had a “state school” stigma until after WWII. Vandaveer Bush made sure they got lots of war research.


> You can do the same thing with a vt220.

Can you? The last I looked at it (a year or two ago), the vt220 in MAME was just the beginning skeleton of an implementation, and it doesn't seem to have been touched much since then. A shame, because AFAIK no "terminal emulator" implements vt220-style sixels (which are different than than the widely-implemented vt4xx-style sixels).


I checked and it was actually the vt240. That one works.


I know the trendy thing is to hide the menu-bar, but it's great for discoverability. Tools→Games→Zone Out


Many flip phones had cameras by then. For instance, the Razr V3 was the best selling phone of 2005, and had a 640×480px camera.


It's not that Cameras didn't exist, more that the technological features were not sophisticated enough to enlist cheating compared to now. A personal OCR Python library wasn't a thing back then.

Not saying that cheating was impossible but uneasy unlike to now where there's a library for everything.


AABBY FineReader was very pirate-able since the early 2000s. The workflow would have been a bit clunky, but it was still very doable.


Nobody argued that it was impossible before. Nor did I claim that there were no cameras before 2005.

Cameras just weren't as ubiquitous as today. Unironically arguing that point is silly. They just weren't (I know you didn't, but we're in a comment chain that made that argument).

Yes, in most groups of people, there were a few of them that had cameras readily available, but it wasn't the norm for everyone.

What was available (not just cameras, but ocr etc pp) was a lot less accessable then it is today - where you just point your phone at it and it transparently extracts you the full text of whatever is on screen/lens, consequently the issue got a lot more problematic and widespread, which was the only thing what was put forward here.


if you are dedicated and smart enough to invest in a small camera pirate OCR software you can probably just do the assignment in the first place...


If you think every student had a razr (btw good luck reading text on tiny screen photo from 640x480 camera) you're pretty privileged;)


To expand on laulis' comment: Valetudo isn't a full custom-firmware, it's a mod for the existing firmware. You copy on the Valetudo daemon binary, fuss with the init scripts to start the daemon, and fuss with the DNS and such to point some domains at 127.0.0.1 to talk to that daemon instead of the normal servers (well, actually you probably download a firmware image from dustbin that already has those modifications applied).

This is a distinction that is worth making because the robot is still running and relying on all of the on-robot proprietary code; it's just the in-cloud code that has been replaced.


it's a bit of a blurry distinction because, what is firmware if not the software that runs on an embedded device? a more accurate description would be that the high-level operating system (HLOS) has been modified to include the installation of a drop-in-replacement for the cloud API. the client side, and whatever hardware abstraction layer lives below it, is untouched. so the client thinks it's talking to the server but it's actually talking to a local open-source server.

I think it's also not quite correct to say the low-level firmware is unmodified, because with vale tudo you rely on the project author to provide a minimal rootkit that gets customized on a per-serial-number basis for the initial rooting.

from a high-level though, it delivers what it says on the tin - cloud features without any requirement of packets leaving your network or even the robot itself.

here's a talk from the author discussing his research https://www.youtube.com/watch?v=AfMfYOUYZvc


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

Search: