6

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?

5
  • I really hate how you are dragging specific types into GENERIC declaration. And what use case would this help with?
    – Euphoric
    Nov 15, 2012 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. Nov 15, 2012 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/… Nov 15, 2012 at 23:35
  • @voroninp In your example are Person and Car actual types, or just values/type constructors? Nov 16, 2012 at 0:01
  • @JimmyHoffa Person and Car are just types, not the values. Nov 16, 2012 at 5:27

4 Answers 4

8

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.

1

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;}
}
4
  • 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. Nov 16, 2012 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? Nov 16, 2012 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 Nov 16, 2012 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. Nov 16, 2012 at 5:29
1

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.

6
  • I don't believe this question is about dependent types. None of the examples in the question require dependent types. Nov 15, 2012 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) Nov 15, 2012 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.. Nov 15, 2012 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. Nov 15, 2012 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. Nov 16, 2012 at 5:36
-2

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.

6
  • 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. Nov 15, 2012 at 23:42
  • 1
    -1: your perspective is much too narrow. Nov 15, 2012 at 23:50
  • @JimmyHoffa Well, then OP shouldn't be using C# as example. But that mathematical basis.
    – Euphoric
    Nov 16, 2012 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, 2012 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, 2012 at 10:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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