Java 8 support multiple inheritance?

I have come across this topic while reading interface in Java 8, there are scenarios where we define method in interface using default or static methods, allowing the next child to either re-define the default method or implement it. Can we say that java supports multiple inheritance to 100%?

Stephan van Hulst

Saloon Keeper

Posts: 7743

142

posted 1 year ago

Static methods are never inherited. As for default methods, what happened when you tried it out? It's not so hard to write a small program that tests this.

The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.

Multiple inheritance was something that the original design of Java consciously omitted.

I was working myself with C++ back around those days and doing projects that had multiple inheritance classes. It could get extremely convoluted and lead to conflicts. If superclass A implements methodX and superclass B implements methodX, but their actions are different, how do you resolve a call on subclass Z's methodX?

Instead of multiple inheritance, Java supports multiple Interfaces. An Interface contains no executable logic, so the fact that 2 interfaces both define methodX is not a problem (as long as there are no signature collisions), since only one actual implementation of methodX is going to occur.

I think I did hear something about putting executable code into interfaces, and yes, that could potentially break things, but I can't find details.

Be very careful about using default interface methods in Java 8. Default interface methods were meant to provide a way to extend an already published interface without breaking untold number of programs already using it prior to the change.

Treat any use of default interface methods that are not motivated by this as highly suspicious and potentially dangerous. I may be wrong but I get a sense that you may be leaning towards a misuse of the default interface method feature just by the way you posed your question. Whatever it is you're thinking of doing, you probably shouldn't do it.

Additionally, the idea of using default methods isn't common (in fact, I would argue it is near zero chance). After all, how many of your colleagues only use default methods, on the chance that you might want to derive from more than one of them? Or do you only code in default methods so that your colleagues can use your code in a "multiple inheritance" way?

Junilu Lacar wrote:Treat any use of default interface methods that are not motivated by this as highly suspicious and potentially dangerous. I may be wrong but I get a sense that you may be leaning towards a misuse of the default interface method feature just by the way you posed your question. Whatever it is you're thinking of doing, you probably shouldn't do it.

Henry Wong wrote:Additionally, the idea of using default methods isn't common (in fact, I would argue it is near zero chance). After all, how many of your colleagues only use default methods, on the chance that you might want to derive from more than one of them? Or do you only code in default methods so that your colleagues can use your code in a "multiple inheritance" way?

I agree that any language feature shouldn't be used to try and bend the rules, but Java interfaces have become like traits in other OO languages since the addition of default methods. Avoiding the use of default methods for anything else but adding new methods to existing interfaces is shooting yourself in the foot, because you're throwing out the many advantages of using traits. Traits use explicit conflict resolution to avoid the diamond problem, which looks like this in Java:

Without overriding Thing.doSomething(), this code would not compile.

From the following code, it should be evident that Java still doesn't (and never will) support multiple inheritance:

The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.

Stephan van Hulst

Saloon Keeper

Posts: 7743

142

posted 1 year ago

1

As a concrete example, here's a *very* generic Tree interface:
Should we *really* have to reimplement degree(), height(), depth(), level(), isRoot() and isLeaf() for every Tree implementation that can't extend AbstractTree for whatever reason?

The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.

Stephan van Hulst wrote:I agree that any language feature shouldn't be used to try and bend the rules, but Java interfaces have become like traits in other OO languages since the addition of default methods. Avoiding the use of default methods for anything else but adding new methods to existing interfaces is shooting yourself in the foot, because you're throwing out the many advantages of using traits.

The problem with prose is that it's wide open to different interpretations. Treating something as suspicious and potentially dangerous is not exactly the same thing as total avoidance.

Since you brought up "shooting oneself in the foot" with total avoidance, people are actually more likely to shoot themselves in the foot if they are not careful in handling a gun than they would be if they didn't handle the gun at all. The same is true with default interface methods. They key to avoiding injury and serious damage in either case is education and mindfulness. Unfortunately, nine out of ten design decisions—probably even more—are ill-informed and ill-considered. One merely has to browse through these forums to see evidence of this.

So, if you were to come to me and lay out a carefully thought out case for using default methods to implement traits, I would say, "OK, let's try it out, test the heck out of it, and see how it goes."

However, if someone comes to me and says, "I think I want to use a default method in this new interface we're publishing...just because I already have an idea for how I would implement it in this particular scenario," then my Spidey senses would be tingling like crazy and I would say, "Stop it right there, buddy! Let go of your mouse and step away from the keyboard!"

Junilu Lacar wrote:However, if someone comes to me and says, "I think I want to use a default method in this new interface we're publishing...just because I already have an idea for how I would implement it in this particular scenario," then my Spidey senses would be tingling like crazy and I would say, "Stop it right there, buddy! Let go of your mouse and step away from the keyboard!"

The same can be said for abstract classes. If you implement a method in an abstract class in such a way that it isn't correct for *all* sub-types of that class, then you should read up on OO some more.

In my example, the implementation of the default methods are correct for *all* trees, regardless of whether they're binary search trees, or ternary min-heaps. A specific subtype can override a default method to provide a more efficient implementation, but even if they don't, the implementation is correct. A default method implementation may not violate its own contract, after all.

My problem with most arguments against default methods is that they're equally applicable to non-final implementations in abstract classes, which people don't seem to mind for some reason.

The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.

It all goes back to proper education and mindfulness (or the lack thereof) in making design decisions. As I said in another recent thread, for me, choosing an abstract class over an interface means I need to pay more attention to inheritance relationships than I would with interfaces. The introduction of default interface methods changes this dramatically so now I also need to be careful about considering inheritance when there are default methods in the interface I want to use. If a default interface method was provided for backwards compatibility with existing implementations, I wouldn't be too concerned. Otherwise, I'd have to carefully study the possible implications to inheritance relationships in my design and exercise due diligence in testing and documenting any related design decisions.

Another key to making default interface methods safe(r), if you really were to use them, is simplicity and singularity in purpose. Default behavior should be simple and easy to understand. Simplicity and singularity in purpose make the intent and behavior of the default method clear(er). Anything less will make a default implementation suspect to me. I would even dare to say that due diligence would require a set of unit tests to be provided for a default interface method to document the designer's original intent and to help others ensure that their implementations of that interface don't violate the Liskov Substitution Principle with respect to the default method.

I took a look at your other post, and it didn't clarify for me what you mean by "inheritance relationships" or why you need to pay careful attention to them. Are you referring to 'self-use'?

I will concede that with default implementations, it's easier to make mistakes that involve circular method invocations. In my example, this would happen when you started off implementing parent() with the following statement:

This would result in a StackOverflowException, because depth() is implemented in terms of parent().

Is this what you're referring to? Otherwise I see no drawbacks in using default methods.

The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.

Stephan van Hulst

Saloon Keeper

Posts: 7743

142

posted 1 year ago

1

Junilu Lacar wrote:Another key to making default interface methods safe(r), if you really were to use them, is simplicity and singularity in purpose. Default behavior should be simple and easy to understand. Simplicity and singularity in purpose make the intent and behavior of the default method clear(er). Anything less will make a default implementation suspect to me. I would even dare to say that due diligence would require a set of unit tests to be provided for a default interface method to document the designer's original intent and to help others ensure that their implementations of that interface don't violate the Liskov Substitution Principle with respect to the default method.

I absolutely agree. But once again I don't think this is a special case for default methods. An API designer can provide tests for any interface method, whether they come with a default implementation or not.

The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.

Stephan van Hulst wrote:I took a look at your other post, and it didn't clarify for me what you mean by "inheritance relationships" or why you need to pay careful attention to them. Are you referring to 'self-use'?

Basically, when designing for inheritance, always consider LSP - this is where inheritance relationships come into play. I'd also keep in mind Josh Bloch's advice to carefully design around inheritance and to prefer delegation over inheritance.

[Edit] For anyone following this discussion: The pitfalls of improperly designing around inheritance are discussed in detail in Bloch's Effective Java Programming book.

Stephan van Hulst wrote:Is this what you're referring to? Otherwise I see no drawbacks in using default methods.

No, not that specifically. As I've already indicated, it's more in consideration for LSP in general.

Maybe I'm just a jaded old developer but in my experience, there's no shortage of people who will advertently or inadvertently discover drawbacks for you with some "clever" implementation based on a misguided interpretation of your API.

All I'm really trying to say is that default interface methods should not be treated lightly. Careful thought and consideration needs to be applied in their design and use because the consequences of a poor decision, if you're publishing an interface for general and widespread consumption, can be significant and long-lasting.

Junilu Lacar wrote:Another key to making default interface methods safe(r), if you really were to use them, is simplicity and singularity in purpose....

I absolutely agree. But once again I don't think this is a special case for default methods. An API designer can provide tests for any interface method, whether they come with a default implementation or not.

Yes, but I reckon it's already been violated by the people who brought usdefault methods.

Take Comparator: A nice simple little interface with one method, and one purpose - to provide an order for an object that either:
(a) Didn't have one.
(b) Is different from the object's "natural" order.

Now it's a 17-method monstrosity (I don't count equals()) with 9 static methods and 7 default ones, whose scope is out of all proportion to the original - in particular now allowing "stacked" ordering, natural orders, reversing, and "policies" for ordering nulls.

And while I have no particular problem with any of this new functionality, to me it isn't "evolution"(*), it's explosion.

Evolution would have been to add comparing() - ie, the functional equivalent of a Comparator, and perhaps reversed(), because it was arguably long overdue; and put all that other stuff in a NEW sub-interface (or maybe two).

And this is my worry - If the people who designed this stuff can't get it right; what chance do the rest of us have?

"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here

Stephan van Hulst

Saloon Keeper

Posts: 7743

142

posted 1 year ago

I don't think it's very fair to blame default methods for that, because ever since we got generics the API exploded with methods that had to do things specially for primitives. If Java had just allowed us to treat primitives as objects, then a lot of the API bloat would never have come to pass.

When it comes to the static utility methods, I think this is a matter of taste. Your opinion is that the single method interfaces we had, should have remained that way, and that utilities should have been added to dedicated utility classes. Personally I prefer that these utility methods are part of the interface they most closely relate to. I don't think the arguments for one carry more weight than arguments for the other. The only thing I think is a shame is that it's not consistent: They put utility methods in the Comparator interface, instead of a Comparators utility class, but then they also put utility methods in the Collectors utility class, and not in the Collector interface.

So if we don't consider the static methods and the overloads for primitives, we're left with one reversed() method and the three thenComparing() methods. They *greatly* improve fluent interface, and I think the benefits you get from the readable and succinct code you can write with them vastly outweighs the cleaner API you get by moving them to a utility class.

The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.

Stephan van Hulst wrote:I don't think it's very fair to blame default methods for that, because ever since we got generics the API exploded with methods that had to do things specially for primitives.

Erm, well yours may have; mine haven't, because I simply ignore primitives when I'm dealing with generics - I regard the two things as incompatible.until Java decides to support primitives (or perhaps structs, as C# does) within the typing system.

If Java had just allowed us to treat primitives as objects, then a lot of the API bloat would never have come to pass.

But I don't see it myself. The only "bloat" I see before version 8 has come in things like Arrays, which probably needed it, since arrays are "separate" from generics anyway.

Your opinion is that the single method interfaces we had, should have remained that way, and that utilities should have been added to dedicated utility classes.

No, I'm saying the utilities that changed the way Comparator works should have been put in a separate interface (or interfaces), and I include naturalOrder() and nullsFirst/Last() in that. To me, the first is simply an implementation of the interface - one I'd already created myself (along with a few others, I suspect) - and the latter is an extension to it.

So if we don't consider the static methods and the overloads for primitives, we're left with one reversed() method and the three thenComparing() methods. They *greatly* improve fluent interface, and I think the benefits you get from the readable and succinct code you can write with them vastly outweighs the cleaner API you get by moving them to a utility class.

I might agree if comparing() and thenComparing() were consistent - ie, they both took a "key extractor" function - but, at least in the tutorial examples they aren't (although both methods appear to have two different versions).
But I still say that thenComparing() is an extension to the interface - again, one I've already created, which I called 'Index'.

Winston

"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here

Stephan van Hulst

Saloon Keeper

Posts: 7743

142

posted 1 year ago

But they are consistent? thenComparing() has a an overload for each overload of comparing(), and only has one extra overload that chains an existing comparator. I can write the following, which is way more fluent than the nested mess I would get with utility methods:

I would actually make nullsFirst()/nullsLast() default methods as well, that take no arguments.

The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.

Stephan van Hulst wrote:But they are consistent? thenComparing() has a an overload for each overload of comparing(), and only has one extra overload that chains an existing comparator. I can write the following, which is way more fluent than the nested mess I would get with utility methods:

OK, well that's not the way they show it in the tutorial (which I seem to have mislaid), so presumably they're using different versions of the two methods.

However, there's another reason why I think that Comparator has turned into a "monster", and I think it's probably due to the fact that the interface wasn't originally defined well enough.

I have already implemented entities that "extend" Comparator to provide the equivalents of every "feature" that was added in version 8 and, personally, I far prefer my approach (which I intend to "functionalize"); but to explain why, I need to start with my design.

1. My view always has been (and still is) that Comparators are an alternative to Comparable, and so should NOT allow nulls. They are (or were) also meant to provide a single ordering to a type, functional or otherwise.

2. Both interfaces should have had a "reversing" method since their inception; and while it's probably too late for Comparable, reversed() is arguably 6 releases too late for Comparator (and definitely 2 too late for me ).

3. If you agree with me about point 1, then "null" ordering is an extension of a Comparator, which can be easily fulfilled with an abstract class that allows it as an option. Mine is called Order, and in my case it also provides a reverse() method. I haven't yet decided whether to take it out or not.

4. NaturalOrder is a concrete (and final) implementation of Order.

5. Combining of Comparators is a whole new behaviour which just happens to provide an order (small 'O'); so I've implemented it as a concrete class called Index that implementsComparator.

Now you may see this as overkill, but to me it keeps to the "single responsibility principle" that we keep banging on to beginners about. The reason that I hate the "new improved" Comparator is that it's lost its focus, and has now become pretty much "anything that provides an order for a type".

The fact is that pretty much every Comparator I now write is an Order, but that just tells me that it was probably a darn good idea.

And all my entities can be easily "functionalized" with a lot less fuss - apart from NaturalOrder, which doesn't need to be.

I am however - you may be glad to know - willing to concede that a "then" method may be a good idea; but it should have been called thenCompare() and defined solely on the basis of a "key extractor" function. And that's how I intend to do it with my Order class.

Winston

"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here

Stephan van Hulst

Saloon Keeper

Posts: 7743

142

posted 1 year ago

Winston Gutkowski wrote:1. My view always has been (and still is) that Comparators are an alternative to Comparable, and so should NOT allow nulls. They are (or were) also meant to provide a single ordering to a type, functional or otherwise.

So let's say I want to add nulls to a TreeSet, how would I do that without a Comparator that accepts null?

2. Both interfaces should have had a "reversing" method since their inception; and while it's probably too late for Comparable, reversed() is arguably 6 releases too late for Comparator (and definitely 2 too late for me ).

String implements Comparable. What could I expect to happen if I called helloWorld.reversed()?

3. If you agree with me about point 1, then "null" ordering is an extension of a Comparator, which can be easily fulfilled with an abstract class that allows it as an option. Mine is called Order, and in my case it also provides a reverse() method. I haven't yet decided whether to take it out or not.

I don't understand what you mean by extension. Regardless, if I had an instance of Comparator, how would I get a new one that orders nulls first?

4. NaturalOrder is a concrete (and final) implementation of Order.

So to get one, I would have to call new NaturalOrder<>()?

5. Combining of Comparators is a whole new behaviour which just happens to provide an order (small 'O'); so I've implemented it as a concrete class called Index that implementsComparator.

I don't understand why it's called Index or how I would use it. Do you have some examples of your orders in action?

Now you may see this as overkill, but to me it keeps to the "single responsibility principle" that we keep banging on to beginners about. The reason that I hate the "new improved" Comparator is that it's lost its focus, and has now become pretty much "anything that provides an order for a type".

Well, that's pretty much what I've always seen it as. Comparators simply ARE "anything that provides an order for a type", that's what they were before Java 8 as well. Some languages call it an Order, and some even have support for a PartialOrder. I think Comparator is a bad name, because it describes what it does and not what it is.

Single responsibility is to improve readability of code. If you have to sacrifice readability (by using constructs such as the new keyword, nested method calls, etc.) just to dogmatically adhere to the single responsibility principle, you're undermining what the principle was intended for.

I am however - you may be glad to know - willing to concede that a "then" method may be a good idea;

but it should have been called thenCompare() and defined solely on the basis of a "key extractor" function.

I think it's a very good convention to name methods that return 'operations' with a present participle. A method named thenCompare() would imply that the comparison was actually the thing being carried out when you call it. It doesn't, it returns an operation that performs the comparison at a later stage. Take this code:

You can very naturally read that as "Sort countries by comparing their capitals, comparing capitals by their population".

If comparing() and thenComparing() didn't provide overloads that accept another comparator, I would have to write the following:

The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.

Stephan van Hulst wrote:I can write the following, which is way more fluent than the nested mess I would get with utility methods...

Bingo. I think I've worked out what I don't like about thenComparing() (and actually, 'then...' methods in general), and that is that they assume a procedural model: "do this ... THEN do this...".

And that is telling someone HOW to perform a function, not - as we are supposed to believe - WHAT it should do. Admittedly at one level removed from the primary source - which is pretty much a Stream, unless I've totally misunderstood how these methods apply in Java.

And the reason I think I'm right is that Java already provides the perfect form for such a method: varargs.
The only reason we have 'then' methods is that someone decided that "fluent" interfaces (something that Java was never designed for) are better, so we have an explosion of methods on interfaces and classes we all thought we knew in version 8, based on the paradigm that "if a function can be done more than once, add a 'then' method".

"What's the problem with that" you might ask. Well, at one stroke, you've just doubled the size of a "functional" API, since presumably every "base" method has to be mirrored by a 'then' method..

Going back to Comparator, how about just:
default int compare(Comparator<T>... keyComparisons) ?
It's precisely what I want: N calls to a Comparator (which is now a functional interface) that does whatever it needs to do to return a comparison value from a pair of values of type (T) that I pass to it, with each successive member only being called if the previous one returned 0.

That's what a "functional" Comparator means to me; not this monstrosity of overloaded and bloated methods that want to please everybody.

Winston

"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here

Stephan van Hulst wrote:So let's say I want to add nulls to a TreeSet, how would I do that without a Comparator that accepts null?

Erm...
First, you can only add ONE null. Second: if you do, you're mad. Third: BEFORE v8, and if you absolutely had to, you'd create a Comparator that allows nulls.

Just one more reason for me to say that v8 logic is extending a Comparator, because we really have no idea what existing ones are doing.

String implements Comparable. What could I expect to happen if I called helloWorld.reversed()?

I presume you mean "helloWorld".reversed(), and I didn't say that it should be CALLED reversed(), I said that a "reverse" method was lacking. Now whether that should be part of the interface, or an overloaded utility method that takes either a Comparable or a Comparator I'm not qualified to answer. My preference (all other things being equal; which they aren't now) is the latter.

I don't understand what you mean by extension. Regardless, if I had an instance of Comparator, how would I get a new one that orders nulls first?

In my world, you simply reverse an Order that orders them last - and it will be a conscious decision - in Java v8, I suspect there's a fair bit of trial and error to get the order you actually want.

So to get one, I would have to call new NaturalOrder<>()?

Yup. Anything wrong with that?

I don't understand why it's called Index or how I would use it. Do you have some examples of your orders in action?

As functional entities, no; because they were never designed that way. I do however have:
Comparator<Person> electoral = new Index(Person.Key,CONSTITUENCY, Person.Key.WARD, Person.Key.SURNAME, Person.Key.FIRSTNAME, Person.Key.MIDDLEINITIAL); and it works brilliantly.
And using enums has an "added" value: Each Comparator has an implicit "name", which can be used for debugging.

Try doing that, in any form, with a "functional" Comparator.

Well, that's pretty much what I've always seen it as. Comparators simply ARE "anything that provides an order for a type", that's what they were before Java 8 as well. Some languages call it an Order, and some even have support for a PartialOrder. I think Comparator is a bad name, because it describes what it does and not what it is.

Which comes back to my initial point: definition.

I think that what Junilu said about "conservatism" has served me well, because I've been able to create a hierarchy that conforms strictly to the notion of a Comparator (as defined by Java), with ALL the stuff that is NOW provided in Java 8 (other than lambdas), without having to compromise anything I'd already written. And furthermore, NOT having default or static methods for interfaces made me really have to think about WHAT I wanted, not HOW it might be done with all the new "goodies".

I should add that I disagree with you not about the definition of a Comparator, but with what Java 8 has done with it. It used to be an order; now it's a "function" with an implicit procedural umbrella, which incorporates all sorts of things it was never intended to.

Single responsibility is to improve readability of code.

What?? No it isn't. It's to improve incremental development, testing, and flexibility. And I say that Java's v8 version of Comparator fails on all three counts. All of a sudden I have 17 methods that I didn't write, that I now have to PROVE work if I decide to use ANY of them. That's not progress, IMO; that's zealotry.

As to your other points, I'll have to answer them later (an hour or two) because I have to go out.

Fun discussion though.

Winston

"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here

Stephan van Hulst wrote:I think it's a very good convention to name methods that return 'operations' with a present participle. A method named thenCompare() would imply that the comparison was actually the thing being carried out when you call it. It doesn't, it returns an operation that performs the comparison at a later stage.

And I say that that is never what a Comparator did before, so you - or the functional paradigm - is changing what it means to "be a Comparator". You are talking about a whole new order of interface.

Tell me Stephen. What changes would it have taken to make Comparator do precisely what it did in version 7 "functionally"?

My reckoning (and I'm still new to v8, but an old hand at Comparators): ONE method (just like before) that takes two objects to be compared in a functional way or via a lambda expression.

But wait...isn't that what the
@FunctionalInterface annotation is all about?

That says to me that the other 17 methods are either
(a) Premature.
(b) Hogwash.
(c) In the wrong interface.
or
(d) Designed to show off just how much you can bastardize an existing interface while still retaining binary compatibility.

Winston

"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here

Stephan van Hulst

Saloon Keeper

Posts: 7743

142

posted 1 year ago

Hey Winston, thanks for your lengthy posts. I didn't get back to you because I've been mulling your ideas over and I can't come up with a reply that would advance the discussion.

For now, let's agree to disagree, and I'm sure we'll lock horns the next time the subject comes up

The mind is a strange and wonderful thing. I'm not sure that it will ever be able to figure itself out, everything else, maybe. From the atom to the universe, everything, except itself.

Stephan van Hulst wrote:Hey Winston, thanks for your lengthy posts. I didn't get back to you because I've been mulling your ideas over and I can't come up with a reply that would advance the discussion.
For now, let's agree to disagree, and I'm sure we'll lock horns the next time the subject comes up

No probs, and I'm sure we will.

I will concede that Comparator is a bit of an oddball because of what it does, but I do worry about interfaces getting littered with default and static methods simply "because we can", and I'd say that their introduction means we have to be even more disciplined about designs rather than less.

Winston

"Leadership is nature's way of removing morons from the productive flow" - Dogbert
Articles by Winston can be found here