2

Idea

I had this idea for a language feature that I think would be useful, does anyone know of a language that implements something like this?

The idea is that besides inheritance a class can also use something called "imprinting" (for lack of better term). A class can imprint one or several (non-abstract) classes. When a class imprints another class it gets all it's properties and all it's methods. It's like the class storing an instance of the imprinted class and redirecting it's methods/properties to it. A class that imprints another class therefore by definition also implements all it's interfaces and it's abstract class.

So what's the point? Well, inheritance and polymorphism is hard to get right. Often composition gives far more flexibility. Multiple inheritance offers a slew of different problems without much benefits (IMO).

I often write adapter classes (in C#) by implementing some interface and passing along the actual methods/properties to an encapsulated object. The downside to that approach is that if the interface changes the class breaks. You also you have to put in a lot of code that does nothing but pass things along to the encapsulated object.

A classic example is that you have some class that implements IEnumerable or IList and contains an internal class it uses. With this technique things would be much easier

Example (c#)

[imprint List<Person> as peopleList]
public class People : PersonBase 
{
    public void SomeMethod()
    {
        DoSomething(this.Count); //Count is from List
    }
}

 //Now People can be treated as an List<Person>
 People people = new People();
 foreach(Person person in people)
 {
  ...
 }

peopleList is an alias/variablename (of your choice)used internally to alias the instance but can be skipped if not needed. One thing that's useful is to override an imprinted method, that could be achieved with the ordinary override syntax

public override void Add(Person person)
{ 
    DoSomething();
    personList.Add(person); 
}

note that the above is functional equivalent (and could be rewritten by the compiler) to:

public class People : PersonBase , IList<Person>
{
    private List<Person> personList = new  List<Person>();


    public override void Add(object obj)
    {
       this.personList.Add(obj)
    }

   public override int IndexOf(object obj)
    {
       return personList.IndexOf(obj)
    }

   //etc etc for each signature in the interface
}

only if IList changes your class will break. IList won't change but an interface that you, someone in your team, or a thirdparty has designed might just change. Also this saves you writing a whole lot of code for some interfaces/abstract classes.

Caveats

There's a couple of gotchas. First we, syntax must be added to call the imprinted classes's constructors from the imprinting class constructor.

Also, what happens if a class imprints two classes which have the same method? In that case the compiler would detect it and force the class to define an override of that method (where you could chose if you wanted to call either imprinted class or both)

So what do you think, would it be useful, any caveats? It seems it would be pretty straightforward to implement something like that in the C# language but I might be missing something :)

Side note - Why is this different from multiple inheritance

Ok, so some people have asked about this. Why is this different from multiple inheritance and why not multiple inheritance. In C# methods are either virtual or not.

Say that we have ClassB who inherits from ClassA. ClassA has the methods MethodA and MethodB. ClassB overrides MethodA but not MethodB.

Now say that MethodB has a call to MethodA. if MethodA is virtual it will call the implementation that ClassB has, if not it will use the base class, ClassA's MethodA and you'll end up wondering why your class doesn't work as it should.

By the terminology so far you might already confused. So what happens if ClassB inherits both from ClassA and another ClassC. I bet both programmers and compilers will be scratching their heads.

The benefit of this approach IMO is that the imprinting classes are totally encapsulated and need not be designed with multiple inheritance in mind. You can basically imprint anything.

gnat
  • 21,442
  • 29
  • 112
  • 288
Homde
  • 11,104
  • 3
  • 40
  • 68
  • 4
    Is there any difference between imprinting and inheritance? More specifically, is there any difference besides syntax in what you're proposing and adding real public inheritance to C#? – David Thornley Mar 01 '11 at 17:57
  • How is this different from multiple inheritance? – Paul Nathan Mar 01 '11 at 17:58
  • There's no virtual calls with this approach and the imprinter can't call anything on the imprintee, only vice versa. Messing with multiple inheritance is pretty complicated business whereas this is simply encapsulation – Homde Mar 01 '11 at 18:03
  • @MKO: For Python users, what's a "virtual call"? This sure sounds like simple multiple inheritance. Please **update** the question with details as to why this isn't must inheritance. – S.Lott Mar 01 '11 at 18:05
  • What are the benefits of this over mixins/traits? There doesn't seem to be that much of a difference. – Matt H Mar 01 '11 at 18:24
  • 2
    @MKO: To make this more clear, could you give a counter-eaxmple? A situation that could be improved by this potential feature? – FrustratedWithFormsDesigner Mar 01 '11 at 18:25
  • I'm not really familiar with mixins and traits. I'll check into that – Homde Mar 01 '11 at 18:29
  • 5
    It sounds a lot like mixins from Ruby (and a few other languages). – mipadi Mar 01 '11 at 18:34
  • Ok, so if I understand Mixins correct the difference here is that you could imprint any class of your choice, not just the ones defined in a module. So in Ruby if you wanted to use some other class's (that might be framework class, thirdparty or your own) method in your class you could do that with imprinting. However a mixin can interact with the class that uses it, while imprinted classes are not even aware of being imprinted. So it's not as flexible but more encapsulated. Also imprints are a way to implement abstract classes and interfaces. – Homde Mar 01 '11 at 18:43
  • @MKO: Mixins, in the languages I've seen them in, are simply specialized classes that you can inherit (and so work on the basis of multiple inheritance). – David Thornley Mar 01 '11 at 18:50
  • Having read the sidenote, I still don't know why imprinting is different from multiple inheritance (except that you're prejudiced against MI), what inherent relation People, PeopleList, and PersonList are supposed to have by virtue of their names, why imprinting is supposed to be proof against things changing outside the class, and what benefit complicating the syntax and semantics would have as opposed to simply allowing multiple inheritance. Voting to close as "not a real question". – David Thornley Mar 01 '11 at 18:58
  • Your argument about breaking changes doesn't seem to be countered by your imprinting technique - if `IList` changed then so would `List`. A class is just as likely to change as an interface. – Matt Ellen Mar 01 '11 at 19:11
  • But it wouldn't break the class if a method was added, removed or changed signature. It would only break if a method who had a declared override would change. – Homde Mar 01 '11 at 19:15
  • @David: Equivalence to MI does not invalidate the question. – Michael K Mar 01 '11 at 19:35
  • @Michael: However, the fact that I don't know what the OP is talking about after looking at the question does invalidate it. If you know what he's talking about, please let me know. The fact that it's equivalent to MI, as far as I can tell, doesn't really invalidate the question, but does reduce my tolerance for bad questions. – David Thornley Mar 01 '11 at 19:47
  • 1
    Basically it's composition vs inheritance and avoiding things like the diamond problem (http://en.wikipedia.org/wiki/Diamond_problem) I'm sorry that I can't describe it clearer for you. – Homde Mar 01 '11 at 19:51
  • @MKO: You could at least post some code that would have a chance of compiling if there was such a thing as imprinting. You imprint `List` as `PeopleList`, say `People` can now be used as a list, and then arbitrarily toss in a `PersonList` without attempting to define it. Either you've messed up your example, or imprinting has some magical effect on class names.ing to define it. – David Thornley Mar 01 '11 at 21:09
  • Hi, PeopleList is just an arbitrary alias I assigned to the imprinted class instance to be able to reference it in the class. It's basically the variable name of the imprinted class, ie it can be whatever you want it to be (as long as it doesn't clash with some other field or property). Sorry for the misunderstanding – Homde Mar 01 '11 at 21:23
  • @MKO: you example would break if `List.Count` was removed, ok so it's a property not a method, but same difference. I don't get what benefit there would be. – Matt Ellen Mar 02 '11 at 09:03
  • If you implemented the class the ordinary way you would have to implement everything in the interface, then if *anything* changes your class would break. With this method it will only break if something you directly reference or override changes. – Homde Mar 02 '11 at 10:12
  • 1
    possible duplicate of [How are mixins or traits better than plain multiple inheritance?](http://programmers.stackexchange.com/questions/250776/how-are-mixins-or-traits-better-than-plain-multiple-inheritance) – gnat Jun 27 '15 at 11:59
  • I don't see how your solution actually improves over multiple inheritance? You say that one issue would be imprinting two classes implementing the same method. Isn't that basically the diamond problem again, just with a compile-time check that some compilers offer for multiple inheritance already? – uliwitness Aug 15 '22 at 11:31

4 Answers4

9

The usual name for this concept is mix-in. It is supported by many languages, but not C# or Java. I would suggest that you learn some new languages, but that may spoil you for C#.

kevin cline
  • 33,608
  • 3
  • 71
  • 142
  • In the languages I'm familiar with that have used mixins (C++ and Common Lisp), it's an application of multiple inheritance. – David Thornley Mar 01 '11 at 19:47
3

That's an interesting feature.

Scala also supports this.

Not exactly the way you're describing it, but it does, take a look at this:

trait  A { 
    def a() = "Hola"
}

trait B { 
    def b() = ", mundo!"
}

class C extends Object with A with  B  {}

object Main { 
    def main( args : Array[String] ) { 
        val c = new C()
        println( c.a() + c.b() );

    }
}

Output:

Hola, mundo!

Python has something similar, but I don't know exactly how it is implemented.

Michael K
  • 15,539
  • 9
  • 61
  • 93
OscarRyz
  • 1,675
  • 3
  • 15
  • 26
2

The behaviour you're looking for is exactly equivalent to multiple inheritance.

The problems you're describing with multiple inheritance in C# are not exactly present in all languages, you can look at some other examples (mixins from ruby have been mentioned already) of how multiple inheritance is implemented to find approaches that might make more sense to you.

It's worth noting that the problems you've described with C# stem from attempts to deal with basic complexities in the configuration - complexities which your imprinting approach does not resolve. In other words, with the imprinting implementation, as you describe it, implementors cannot yet ignore the same complexities that exist in multiple inheritance. Say that you imprint both PeopleList and ChemistList. Which "count" message will be sent in your example? I think you'll find that once you've considered this, and all the other corner cases, of your implementation, you will end up with an exact copy of the multiple inheritance functionality, with a different name.

blueberryfields
  • 13,200
  • 8
  • 51
  • 87
  • As I mentioned in the post, if a class imprints more than one class with overlapping signature it has to explicitly declare an override. I guess the other difference is that an imprinted class cannot call virtual methods on the class that's imprinting it therefore it's completely encapsulated which reduces complexity. Furthermore if C# had multiple inheritance you'd have to depend on the classes you inherit to have virtual methods. If you look at the functionally equivalent code you see that it's more of a convenience than changing behavior. – Homde Mar 01 '11 at 19:13
  • @MKO: And, if you have multiple inheritance in C++, and you have two different inherited member functions with identical names and signatures, you think this will work without an override? (BTW, what is the point about not calling virtual functions on the inheriting class? Isn't that going to be surprising, and therefore undesirable, behavior?) – David Thornley Mar 01 '11 at 19:52
  • It sounds like you've learned of one implementation of multiple inheritance in C#, didn't like it, and decided to go a different route, calling it something else. The alternative you came up with is still, however, a multiple inheritance implementation. It looks like, on the spectrum of MI, it sits somewhere between what's available in C++ and what's available in Ruby. The convenience you speak of is exactly the motivation for multiple inheritance in the first place. I still claim that if you deal with all the corner cases, you'll end up back at your original MI definition. – blueberryfields Mar 01 '11 at 19:55
  • 1
    David, typically with MI there's some kind of automatic conflict resolution. Since the class just encapsulates the classes it "imprints" it doesn't matters. That's the point, imprinted classes doesn't have to be specifically designed and intermixed with other classes, they're simply encapsulated. – Homde Mar 01 '11 at 19:56
  • yeah, it might be that this is just a solution to a very c# specific problem – Homde Mar 01 '11 at 19:57
  • though I would add that you could make a case for building a language on just interfaces and imprinting rather than inheritance altogether. – Homde Mar 01 '11 at 19:58
  • If we're talking very metaphorically I'd say the difference between inheritance and "imprinting" is that a Truck *is* a vehile, but a Tank *has* a cannon (but is also a vehicle) :) – Homde Mar 01 '11 at 20:01
  • @MKO: I prefer to think of (traits | roles | imprints) in terms of *does* instead of *has*. A Vehicle does Drive. A Truck is-a Vehicle. A Tank is-a Vehicle. A Tank has-a cannon. A Truck does Shoot. But a different kind of Tank could have a Laser, but it still would conform to the Shoot behaviour. – phaylon Mar 02 '11 at 16:19
2

Perl 5 has the Moose OO system, which provides roles (sometimes also called "traits," which I think stems from the original academic background.) This includes method and attribute composition, as well as conflict detection and resolution like you specified.

phaylon
  • 647
  • 3
  • 7