Live data from Hacker News

Why most “clever” code ain’t so clever after all

drive.google.com

91–100 of 104 posts

Re: Why most “clever” code ain’t so clever after all

#91

Earlier quoted context omitted.

Java is a quite awful language honestly. And I use it everyday at work. Generics implementation with type erasure is a pain and complicates things a lot. There is no automatic static type inference and before Java 7 you had to specify twice the generic types in the same statement. This adds a lot of "complexity" or noise when reading some code. Checked exceptions..do we want to speak about all the complexity that the…

I think there's two definitions of simple being used between you and I. Let's use different words instead: obviousness and terseness. Obviousness is how clear the goal of the code is; terseness is how much typing it takes to get there. I'm using simple to mean obviousness; this seems to be in line with the article, as being "clever" typically means exchanging obviousness for terseness. You seem to be taking terseness…

I don't think Java is obvious at all apart the aforementioned simple statements. With generics you have actually no idea of what type you receive at runtime, you receive just an object. If the goal of the code is to return some sensible default for a specific type in Java you cannot use generics. And it's not obvious at all for anyone that doesn't know the generics implementation details. About closures, do you think that it is more obvious to define an entire anonymous inner class when you really just need to define a method delegate or an anonymous method? For me it's completely counterintuitive other than it makes my eyes bleed. If I need a local variable I obviously define it, I don't create a class which exposes an encapsulated field and use it. And it's exactly the same thing when I need an anonymous method. When the goal is reading a file why should be more obvious to create a buffered reader that encapsulates a file reader that wraps a file and use it to read when I can just do File.ReadAllLines() in C#? What is the added value of calling stream() on everything before using any enumerable? In C# obviously you just call Extension Methods on an IEnumerable. You even get IntelliSense. Why should be obvious to call stream() on an object that is already a collection?

Re: Why most “clever” code ain’t so clever after all

#92

Earlier quoted context omitted.

Composition increases boilerplate code. With simple inheritance hierarchies there is an inherent advantage in this regard. If you use inheritance you don't need to encapsulate the "base" object and implement all the methods of the interfaces doing most of the time just a routing to the base object, you can just extend from the abstract base object and implement only the methods that you need. Obviously if your hierar…

> If someone says Composition > Inheritance it is like saying Screwdriver > Hammer, a complete non-sense. You're stretching a bit too far. Inheritance is nothing but composition with some default implicit virtual method routing. You admit as much in your comment. If you want tools, it's more like a hammer vs a mallet and a prybar. Same tools, same purpose, just one is bundled.

The purpose is completely different. You use interfaces and composition to decouple the implementation of some objects, you use inheritance to define some object hierarchy. Inheritance specifies the is a relationship, Composition the has a. As you can see these two are totally different concepts.

Re: Why most “clever” code ain’t so clever after all

#93

Earlier quoted context omitted.

> If someone says Composition > Inheritance it is like saying Screwdriver > Hammer, a complete non-sense. You're stretching a bit too far. Inheritance is nothing but composition with some default implicit virtual method routing. You admit as much in your comment. If you want tools, it's more like a hammer vs a mallet and a prybar. Same tools, same purpose, just one is bundled.

The purpose is completely different. You use interfaces and composition to decouple the implementation of some objects, you use inheritance to define some object hierarchy. Inheritance specifies the is a relationship, Composition the has a . As you can see these two are totally different concepts.

What is an is a relationship? It is the promise that a type implements a contract. That sounds like an interface to me; implementing interfaces also forms is a relationships. Allow interfaces to be externally defined for a type, and now you have Haskell classes or Rust traits. This isn't a new idea I'm proposing here; it's quite workable and very straight-forward.

EDIT: To be clear, in inheritance, the contract being implemented is the implicit contract specified by the parent type. (Assuming you're following the Liskov substitution principle, which you should be.)

Re: Why most “clever” code ain’t so clever after all

#94

Earlier quoted context omitted.

I think there's two definitions of simple being used between you and I. Let's use different words instead: obviousness and terseness. Obviousness is how clear the goal of the code is; terseness is how much typing it takes to get there. I'm using simple to mean obviousness; this seems to be in line with the article, as being "clever" typically means exchanging obviousness for terseness. You seem to be taking terseness…

I don't think Java is obvious at all apart the aforementioned simple statements. With generics you have actually no idea of what type you receive at runtime, you receive just an object. If the goal of the code is to return some sensible default for a specific type in Java you cannot use generics. And it's not obvious at all for anyone that doesn't know the generics implementation details. About closures, do you think…

> With generics you have actually no idea of what type you receive at runtime, you receive just an object.

That's kind of the point of generics? I don't understand this argument at all. If you need a specific kind of type, then bound the generic using `extend` and you can use the bounding type's methods and fields. [0]

You're still using a different definition of obvious, despite my having defined it for this use case. For instance:

> Why should be obvious to call stream() on an object that is already a collection?

That's the very definition of obvious. You are making it quite clear that you intend to use this collection as a stream. It's extremely obvious. Same with the buffered reader; Readers are unbuffered, and it's very obvious that you are buffering the reader when you wrap it. (Also, Java has `java.nio.Files.readAllLines` [1], so I'm not sure what you're going on about.)

Extention methods are very non-obvious; where is an extension method defined? The answer is anywhere; it can live in any type you imported. It's not obvious looking at the line of code where execution is going to flow. (And yes, an IDE will track it down for you. Just because an IDE can do the work for you, doesn't mean that there's not work to be done.)

[0] http://docs.oracle.com/javase/tutorial/java/generics/bounded...

[1] http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files...

Re: Why most “clever” code ain’t so clever after all

#95
post #75

This article hinges on a rather silly fallacy. Luckily the author does us the favor of making his mistake very clear in the curve-fitting analogy; but first look at the code. He gives several examples of poorly-written FP code (which we're supposed to believe is "clever" by virtue of being FP), then introduces some new problem constraint which is carefully selected to make the FP solution break but some equally ridic…

But with mathematics, nitpicking is ~kind of~ the point. For example when dealing with real numbers, you can get away with defining Compact sets as bounded and closed sets; however when you enter a different Topological space, that definition will surely fall apart. So in retrospect, defining compact as bounded and closed was working in your limited test cases (real numbers) but in the real world you really have to e…

> that definition will surely fall apart

In what sense could that even conceivably be a true statement? I could define compact sets as sets which make me think of the color purple and it would be a completely valid definition. Nothing will fall apart. I think you are vaguely referring to the fact that proofs concerning compact sets in general topological spaces are not valid if you replace compact sets with bounded and closed sets, but that's just confusing the term "compact set" with what it refers to; the proofs aren't about the term but about the thing, which doesn't change. If "compact set" meant "bounded and closed" and, say, "cover-compact set" referred to sets where (ahem) every open cover has a finite subcover, then the concept of "cover-compact" will have certain general proofs associated to it and the term "compact" will have a different collection of general proofs associated to it.

So in some ways you're making the same mistake the author did: carefully selecting a certain way to generalize a concept (real -> topological) and a certain ill-conceived claim about the original concept (compact=bounded and closed), and then acting all surprised when, oops!, the claim doesn't generalize.

Re: Why most “clever” code ain’t so clever after all

#96

Earlier quoted context omitted.

The purpose is completely different. You use interfaces and composition to decouple the implementation of some objects, you use inheritance to define some object hierarchy. Inheritance specifies the is a relationship, Composition the has a . As you can see these two are totally different concepts.

What is an is a relationship? It is the promise that a type implements a contract. That sounds like an interface to me; implementing interfaces also forms is a relationships. Allow interfaces to be externally defined for a type, and now you have Haskell classes or Rust traits. This isn't a new idea I'm proposing here; it's quite workable and very straight-forward. EDIT: To be clear, in inheritance, the contract being…

you were not speaking about interfaces, you were speaking about composition. As I said composition and inheritance are two completely different concepts. And I'm not making up the definitions, is a and has a are very well known concepts in computer science. You can argue ad libitum, but this doesn't change the definition. https://en.m.wikipedia.org/wiki/Has-a https://en.m.wikipedia.org/wiki/Is-a

Re: Why most “clever” code ain’t so clever after all

#97

I run a small dev company. This is the first lessons we teach our programmers. If your code cant be understood by someone else with minimal efforts it is not good enough.

This is a very delicate subject. If the program is using language constructs and can't be understood because the reading programmer doesn't know it, then who's fault is it? why have multiline if/else when a tenary operator can do? I rather read a = b ? c : d; than possibly 4 lines of code, p/s ignore the names of the variable. There are plenty of code out there that are so easy to understand if you read them one line…

Bertrand Meyer and a few other notables talk about separating decisions (policy) from execution, which happens to address some of those issues, because the decide and act become sibling function calls instead of a deeply nested chain of responsibility arrangement.

It also happens to make testing a lot easier.

It's probably just a crystalization of the old idea of keeping business logic out of your code, but somehow misses the open invitation to create rules engines...

Re: Why most “clever” code ain’t so clever after all

#98

Earlier quoted context omitted.

What is an is a relationship? It is the promise that a type implements a contract. That sounds like an interface to me; implementing interfaces also forms is a relationships. Allow interfaces to be externally defined for a type, and now you have Haskell classes or Rust traits. This isn't a new idea I'm proposing here; it's quite workable and very straight-forward. EDIT: To be clear, in inheritance, the contract being…

you were not speaking about interfaces, you were speaking about composition. As I said composition and inheritance are two completely different concepts. And I'm not making up the definitions, is a and has a are very well known concepts in computer science. You can argue ad libitum, but this doesn't change the definition. https://en.m.wikipedia.org/wiki/Has-a https://en.m.wikipedia.org/wiki/Is-a

I'm starting to feel like you're not actually reading anything I write. I specifically include interfaces. To quote myself:

> Also, maybe eliminate inheritance and force interfaces and composition instead.

Implementing an interface meets all the conditions of an is a relationship; no redefinition is necessary. [0] After all, interfaces are nothing more than abstract base classes with no method bodies to inherit. I haven't argued anywhere that composition defines an is a relationship, so I have no idea where you're pulling that from.

[0] https://en.m.wikipedia.org/wiki/Is-a#Java

EDIT: I really like this article you linked. It has all sorts of things that help me prove my point. For instance, the Rectangle example from the LSP section. If Rectangle were an interface:

    interface IRectangle {
        double getWidth();
        double getHeight();
    }
It's trivial to implement concrete Rectangle and Square classes that don't violate any principles. Inheritance, on the other hand, is pretty much guaranteed to be broken as long as Rectangle is mutable, because Square cannot add additional constraints to Rectangle and still pretend to be a Rectangle in all use-cases.

Re: Why most “clever” code ain’t so clever after all

#99

Earlier quoted context omitted.

I don't think Java is obvious at all apart the aforementioned simple statements. With generics you have actually no idea of what type you receive at runtime, you receive just an object. If the goal of the code is to return some sensible default for a specific type in Java you cannot use generics. And it's not obvious at all for anyone that doesn't know the generics implementation details. About closures, do you think…

> With generics you have actually no idea of what type you receive at runtime, you receive just an object. That's kind of the point of generics? I don't understand this argument at all. If you need a specific kind of type, then bound the generic using `extend` and you can use the bounding type's methods and fields. [0] You're still using a different definition of obvious, despite my having defined it for this use cas…

The point of generics is to pass generic arguments to a method/class, as the name says. In Java you are losing every type information and at runtime your method will accept objects, not arguments with a generic type. There are several situation in which preserving the type information is extremely useful. For this reason in Java you still find a lot of libraries that receive a type as argument, while in C# you can just specify the generic type. For me it is far more obvious in the c# way given that I cannot see why I should pass the type of an argument in a generic method. For the streams it is honestly ridiculous. I want to apply a filter, a map, a reduce or wathever to an Iterable. The stream is a very well known and completely different concept and it is widely used in reactive programming, they just stole that concept to use it in a completely non obvious way. For the other streams I still can't see how it is obvious that I should do manually all that wrapping that is completely counterintuitive and makes you lose track of the code purpose. Finally extension methods are perfectly obvious. They are just syntactic sugar for static methods, I hope that at least you agree that static method are the gist of obviousness.

Re: Why most “clever” code ain’t so clever after all

#100

Earlier quoted context omitted.

you were not speaking about interfaces, you were speaking about composition. As I said composition and inheritance are two completely different concepts. And I'm not making up the definitions, is a and has a are very well known concepts in computer science. You can argue ad libitum, but this doesn't change the definition. https://en.m.wikipedia.org/wiki/Has-a https://en.m.wikipedia.org/wiki/Is-a

I'm starting to feel like you're not actually reading anything I write. I specifically include interfaces. To quote myself: > Also, maybe eliminate inheritance and force interfaces and composition instead. Implementing an interface meets all the conditions of an is a relationship; no redefinition is necessary. [0] After all, interfaces are nothing more than abstract base classes with no method bodies to inherit. I ha…

You wrote this: "Inheritance is nothing but composition with some default implicit virtual method routing." In response to my post where I said that inheritance and composition are two different tools and doesn't make sense to say that one is always better than the other. So it seems to me that you think that inheritance and composition are the same concepts given your words that I quoted and given that you were arguing with my definition of different tools.

Edit: I don't see any composition in your example, just an interface implementation.

Post reply on HN