Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Consider the following generic class:

public class EntityChangeInfo<EntityType,TEntityKey>
{
    ChangeTypeEnum ChangeType {get;}
    TEntityKeyType EntityKey {get;}
}

Here EntityType unambiguously defines TEntityKeyType. So it would be nice to have some kind of types' map:

public class EntityChangeInfo<EntityType,TEntityKey> with map 
  < [ EntityType : Person -> TEntityKeyType : int]
    [ EntityType : Car -> TEntityKeyType : CarIdType ]>
{
    ChangeTypeEnum ChangeType {get;}
    TEntityKeyType EntityKey {get;}
}

Another one example is:

 public class Foo<TIn> with map
< [TIn : Person -> TOut1 : string, TOut2 : int, ..., TOutN : double ]
  [TIn : Car -> TOut1 : int, TOut2 :int, ..., TOutN : Price ] >
    {
        TOut1 Prop1 {get;set;}
        TOut2 Prop2 {get;set;}
        ...
        TOutN PropN {get;set;}
    }

The reasonable question: how can this be interpreted by the compiler? Well, for me it is just the shortcut for two structurally similar classes:

public sealed class Foo<Person>
{
    string Prop1 {get;set;}
    int Prop2 {get;set;}
    ...
    double PropN {get;set;}
}

public sealed class Foo<Car>
{
    int Prop1 {get;set;}
    int Prop2 {get;set;}
    ...
    Price PropN {get;set;}
}

But besides this we could imaging some update of the Foo<>:

public class Foo<TIn> with map
    < [TIn : Person -> TOut1 : string, TOut2 : int, ..., TOutN : double ]
      [TIn : Car -> TOut1 : int, TOut2 :int, ..., TOutN : Price ] >
        {
            TOut1 Prop1 {get;set;}
            TOut2 Prop2 {get;set;}
            ...
            TOutN PropN {get;set;}

            public override string ToString()
            {
                 return string.Format("prop1={0}, prop2={1},...propN={N-1},
                                         Prop1, Prop2,...,PropN);
            }
        }

This all can seem quite superficial but the idea came when I was designing the messages for our system. The very first class. Many messages with the same structure should be discriminated by the EntityType.

So the question is whether such construct exists in any programming language?

share|improve this question
    
I really hate how you are dragging specific types into GENERIC declaration. And what use case would this help with? –  Euphoric Nov 15 '12 at 22:25
    
@Euphoric Consider I have a bunch of messages with the same structure: ModificationType and EntityKey. EnityKey can be complex or simple - just an int. And if we have 100 entities with different key types we must create many classes which will differ only by the type of one property. Here the type of the class serves as the param for the messaging system. –  voroninp Nov 15 '12 at 22:32
2  
If I understand correctly, you're talking about dependent types, which is definitely not superficial. The languages which implement this functionality are quite nutty powerful and complex. Have a look at my answer and let me know if this is not what you're referring to; I think it is. You won't find a lot of info about it that makes much sense as it's a currently researched domain space among language and type theorists, here's an example of the stuff you'll find "Parametricity for dependent types": 3.bp.blogspot.com/-TTUpEQC9aVA/T74LMtEN4VI/AAAAAAAAARs/… –  Jimmy Hoffa Nov 15 '12 at 23:35
    
@voroninp In your example are Person and Car actual types, or just values/type constructors? –  Jimmy Hoffa Nov 16 '12 at 0:01
    
@JimmyHoffa Person and Car are just types, not the values. –  voroninp Nov 16 '12 at 5:27
add comment

4 Answers

up vote 8 down vote accepted

Yes, this facility does exist in some programming languages.

For example, in Haskell, these are called Functional Dependencies (fundeps are not part of Haskell 98, but they are supported in common implementations like GHC)

In C++, you can achieve this kind of thing with traits classes.

share|improve this answer
add comment

I think you are using generics for something that they were not intended and designed for.

Generics are to allow caller to create specific type from generic pattern. The generic type should never know what type caller will put in. It can limit those types, but never know exact types. Think how would you use those types? You cannot pass this to anything else, because it would mean this something else too needs to be generic and then you get "generic creep" where generic types get propagated through structure. I was there and it is not good at all.

What you are trying to achieve is extremely similar to code generation. You can use T4 or something and generate all required classes from some kind of definition. You should really forget about generics and think in pure OOP. Find something all those messages have in common that the message system can use and implement concrete class for each message type. This will make the design much more flexible, because you are not limited to two fields and will be much cleaner.

share|improve this answer
1  
-1 Generics came from functional programming not OOP; more specifically they came from math. In math where they originated from they are actually used to do a great deal more than we use them for in OOP. There purpose can be many more things than the narrow set we're used to. –  Jimmy Hoffa Nov 15 '12 at 23:42
1  
-1: your perspective is much too narrow. –  kevin cline Nov 15 '12 at 23:50
    
@JimmyHoffa Well, then OP shouldn't be using C# as example. But that mathematical basis. –  Euphoric Nov 16 '12 at 6:49
    
@kevincline No, I just had my share of experience working with generics in C# and once tried doing what OP is doing. It resulted in really bad architecture. If OP wants to have heavy metaprograming capabilities, then he shouldn't be using C#. –  Euphoric Nov 16 '12 at 6:51
    
I kind of agree with @Euphoric: the mixture of C# with something that looks like Funcdeps is not good. I kind of disagree in considering that OOP is a good answer always, but then, OOP tends to scale better than FP (if FP=<Haskell-by-the-average-Joe>). –  dsign Nov 16 '12 at 10:13
show 1 more comment

John Bartholomew's answer is the correct exposition of the technique you're referring to.

Leaving this incorrect answer here for a short while for posterity as it's relevant related content. Will probably delete tomorrow when you've had time to review the information in case it's valuable to you :)


There are a class of functional languages with a related concept, referred to as "dependent types" the idea being you can create functionality that depends on particular values of a type rather than just the type itself. (that is my very limited description of the concept; crazy math-nuts people can speak to this more)

Here's the wikipedia for some further reading, it lists a hand full of languages which implement dependent types.

One of the biggest uses of dependent types as I understand them is for proofs, which makes sense if you think about it and is similar to what you're trying to use it for; you're trying to constrain the types to get specific functionality in your type out of a type passed to you; dependent types works similarly but constraining down to the value level which is a very hardy constraint you could see being useful in the context of proving things are interacting in a strictly defined way.

Please; anyone more familiar with the concept of dependent types correct me if I'm off in my understanding. It's a very high level concept and not one I've direct experience with beyond my addiction to reading about various languages, I wouldn't want to be giving incorrect information here.

share|improve this answer
    
I don't believe this question is about dependent types. None of the examples in the question require dependent types. –  John Bartholomew Nov 15 '12 at 23:47
    
@JohnBartholomew if you understand them, is my explanation of them accurate at a high level? If the OP says this type of functionality is not what he was looking for I'll delete my answer; it's just the first thing that came to mind (though I haven't touched FunDeps yet in haskell so I can't speak to whether or not that's a more accurate fit, it may be spot on, I just don't know) –  Jimmy Hoffa Nov 15 '12 at 23:50
    
@JohnBartholomew I could be wrong; but in my understanding of his pseudo-code Car and Person are values (or type constructors) not types themselves, if that's not the case then I would agree with my understanding of dependent types this wouldn't fit.. –  Jimmy Hoffa Nov 15 '12 at 23:53
1  
My understanding of the example code was that Person and Car are types. Probably best to wait for the OP to clarify or respond. –  John Bartholomew Nov 15 '12 at 23:57
    
@JohnBartholomew Yes, you understood me correctly. Car and Person are types, so what I need is to establish some 'type function' which input parameter defines the types of the properties i.e. gives the vector of types. If we speak about entities each entity's type defines the Tuple<TKeyPart1Type,..,TKeyPartNType> - entity's key. And functional relational between TEntityType -> Tuple<...> can be set. –  voroninp Nov 16 '12 at 5:36
show 1 more comment

Well...you could just close the types for convenience:

public class EntityChangeInfo<TEntityType,TEntityKey>
{
    ChangeTypeEnum ChangeType {get;}
    TEntityKeyType EntityKey {get;}
}

public class PersonChangeInfo : EntityChangeInfo<Person,int>
{
}

public class CarChangeInfo : EntityChangeInfo<Car, CarIdType>
{
}

Though, it seems something like this would be more flexible:

public **interface** IEntityChangeInfo<TEntity,TEntityKey>
{
    ChangeTypeEnum ChangeType {get;}
    TEntityKey EntityKey {get;}
    TEntity Entity {get;}
}

Also, this might be language dependent but I would suggest that even if you use an enum internally for convenience, you NOT expose the enum in the contract.

public **interface** IEntityChangeInfo<TEntity,TEntityKey>
{
    int? ChangeTypeId {get;}
    TEntityKey EntityKey {get;}
    TEntity Entity {get;}
}

or

public **interface** IEntityChangeInfo<TEntity,TEntityKey,TChangeType>
{
    TChangeType ChangeType {get;}
    TEntityKey EntityKey {get;}
    TEntity Entity {get;}
}
share|improve this answer
1  
I'm not certain that the poster was asking for how to solve the problem so much as if a technique he was trying to describe existed as a facility provided by any languages, though that was my interpretation of his question and it may be incorrect. –  Jimmy Hoffa Nov 16 '12 at 0:18
    
Oh, you mean, do any languages allow you to constrain multiple generic types with each other? Like, if T1 is SomeConcreteType T2 must be string? –  Ed Hastings Nov 16 '12 at 1:01
    
That was my understanding yes, I understood the constraint to be value based but as John pointed out he may have meant a type constraint, he really didn't specify –  Jimmy Hoffa Nov 16 '12 at 5:02
    
You are both right =) Was thinking over the hierarchy of classes and became curious about language facility. I apologise for the vagueness of my question, but it's quite difficult to ask something completely unknown. –  voroninp Nov 16 '12 at 5:29
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.