Jump to content
  • Advertisement
Sign in to follow this  
NightCreature83

Moving a generic function into an interface

This topic is 2585 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

A have a derived class that is a generic type now I would like to promote certain get and set functions up to the base class. However these get and sets wouldn't know what type they would be returning so these would have to be generic. Now what I want is for the implementation that the generic derived type is giving to be the one that is used for the base class methods. I want to avoid having to cast my interface to the derived generic type, the reason behind this is that the T value can be instantiated with a, for example, model class another one however is instantiated with a UIModel which in turn is derived from Model.

The following code is an example of what I want this doesn't compile however, and I know to little about C# generics to fix it.

[source lang="csharp"]
public abstract class IAttributeHandle : Handle
{
public IAttributeHandle() : base()
{
}
public IAttributeHandle(String name) : base(name)
{
}
public abstract T Value<T>();
public abstract void setValue<T>(T value);
}

public abstract class AttributeTypeHandle<T> : IAttributeHandle
{
public AttributeTypeHandle() : base()
{
m_type = typeof(T);
}
public AttributeTypeHandle(String name, T value) : base(name)
{
m_type = typeof(T);
m_value = value;
}
public override T Value<T>()
{
return m_value;
}
public override void setValue<T>(T value)
{
m_value = value;
}
protected T m_value;
}
[/source]

There are more derived types of this class with definitions like the following:

[source lang="csharp"]

class BoolHandle : AttributeTypeHandle<bool>

{

}

[/source]

PS: not sure whats gone wrong but the highlight tags won't work for me :(

Share this post


Link to post
Share on other sites
Advertisement

Make it generic: IAttributeHandle<T>

Thats what I want to avoid as I don't want to write code that goes:
IAttributeHandle<String> stringHandle = <get handle in a generic manner>;

This requires me to know the Type of the handle I am getting which I don't know in some cases.

Share this post


Link to post
Share on other sites
I don't think this is logically possible. You can have 'get' if you a covariant type parameter, 'set' if it's contravariant. You can't have both unless you know the underlying type. (Consider: you can convert an IAttributeHandle to a UIModel to an IAttributeHandle to a Model, allowing you to 'get' it, but you can't then use set because you can't assign a Model to a UIModel.)

If you can live with that restriction, then you can do something like this:

[source lang="csharp"]interface IGettable<out T>
{ T Value { get; } }

interface ISettable<in T>
{ T Value { set; } }

abstract class Handle<T> : IGettable<T>, ISettable<T>
{ /* ... */ }

// ...

IGettable<Model> h = uiModel.getHandle();
ISettable<UIModel> h = model.getHandle();[/source]

Share this post


Link to post
Share on other sites

I don't think this is logically possible. You can have 'get' if you a covariant type parameter, 'set' if it's contravariant. You can't have both unless you know the underlying type. (Consider: you can convert an IAttributeHandle to a UIModel to an IAttributeHandle to a Model, allowing you to 'get' it, but you can't then use set because you can't assign a Model to a UIModel.)

If you can live with that restriction, then you can do something like this:

[source lang="csharp"]interface IGettable<out T>
{ T Value { get; } }

interface ISettable<in T>
{ T Value { set; } }

abstract class Handle<T> : IGettable<T>, ISettable<T>
{ /* ... */ }

// ...

IGettable<Model> h = uiModel.getHandle();
ISettable<UIModel> h = model.getHandle();[/source]

You misunderstand the hierarchy here a little bit and maybe I didn't make it clear enough but the Model and UIModel aren't part of the IAttributeHandle hierarchy they are the instantiated T values. Model and UIModel define their own heirarchy. So the hierarchies are Model <- UIModel and Handle <- IAttributeHandle <- AttributeTypeHandle<T> <- AttributeModelHandle (T is defined as a model for this).

What I would like to have is a get more then a set on the IAttribute that allows me to return the value it is storing without having to specify T or cast to AttributeTypeHandle. This might not be possible as you are mentioning and it might be that my hierarchy is broken in this case and there is a simpler solution to the problem.

As an aside these handles do more then just store a name (this is hashed), value pair they are also de/serialiseable and take care of the de/serialisation for type T.

Share this post


Link to post
Share on other sites
You misunderstand the hierarchy here a little bit


Nope, the way you describe it is the way I understood it.

What I would like to have is a get more then a set on the IAttribute that allows me to return the value it is storing without having to specify T or cast to AttributeTypeHandle.[/quote]

What do you want to then do with that value? If you want to treat it as more than an Object, without casting, then you're going to have to return either the underlying type, or some less-derived type. The code I posted gives you that:

[source lang="csharp"]interface IGetter<out T> { T Value { get; } }
interface ISetter<in T> { T Value { set; } }

abstract class IAttributeHandle<T> : Handle, IGetter<T>, ISetter<T>
{ /* as it is */ };

class Model
{
// ...
public IAttributeHandle<Model> Handle
{ get; }
}

class UIModel
{
// exact detail depends on how you create an IAttributeHandle
public new IAttributeHandle<UIModel> Handle
{ get; }
}

// ...

void DoSomethingWithModel(IGetter<Model> m)
{ /* something */ }

// ...

IAttributeHandle<UIModel> m = /* something */;
DoSomethingWithModel(m);[/source]

The only way to get away from this would be to use dynamic types.

Share this post


Link to post
Share on other sites

[quote name='NightCreature83' timestamp='1321521508' post='4884899']You misunderstand the hierarchy here a little bit


Nope, the way you describe it is the way I understood it.

What I would like to have is a get more then a set on the IAttribute that allows me to return the value it is storing without having to specify T or cast to AttributeTypeHandle.[/quote]

What do you want to then do with that value? If you want to treat it as more than an Object, without casting, then you're going to have to return either the underlying type, or some less-derived type. The code I posted gives you that:

[source lang="csharp"]interface IGetter<out T> { T Value { get; } }
interface ISetter<in T> { T Value { set; } }

abstract class IAttributeHandle<T> : Handle, IGetter<T>, ISetter<T>
{ /* as it is */ };

class Model
{
// ...
public IAttributeHandle<Model> Handle
{ get; }
}

class UIModel
{
// exact detail depends on how you create an IAttributeHandle
public new IAttributeHandle<UIModel> Handle
{ get; }
}

// ...

void DoSomethingWithModel(IGetter<Model> m)
{ /* something */ }

// ...

IAttributeHandle<UIModel> m = /* something */;
DoSomethingWithModel(m);[/source]

The only way to get away from this would be to use dynamic types.
[/quote]

See the problem starts in code like this which is in the render component.

[source lang="csharp"]

IAttributeHandle model = entity.getAttribute(FNVHash.hashString("model"));

AttributeHandleModel modelHandle = (AttributeHandleModel)model;
Model modelValue = modelHandle.Value();

[/source]


At this side I don't know what model is stored in the handle all i know it is a Model or one of it's derived classes, I am only interested in the Model exposed functions however.

The problem however here is that it can't cast to that at runtime :( and as there is no getter in the IAtributeHandle there is no way I could get the Value which I know is a Model or a derived version of a model. Maybe my problem is just in the instantiations of the Handles in this case and I should just be storing AttributeModelHandles instead of AttributeUIModelHandle.

Share this post


Link to post
Share on other sites
[source lang="csharp"]

IAttributeHandle model = entity.getAttribute(FNVHash.hashString("model"));

AttributeHandleModel modelHandle = (AttributeHandleModel)model;
Model modelValue = modelHandle.Value();

[/source]


I don't think I'm quite understanding why this can't be

[source lang="csharp"]IGetter<Model> model = entity.getAttribute(FNVHash.hashString("model"));
Model modelValue = model.Value();[/source]
?

In practice, you'd probably want a more diamond-shaped tree for the handles, with both IGetter and ISetter extending some other interface, but this would allow you to do everything you've described so far.

Share this post


Link to post
Share on other sites

[quote name='NightCreature83' timestamp='1321553384' post='4885039'][source lang="csharp"]

IAttributeHandle model = entity.getAttribute(FNVHash.hashString("model"));

AttributeHandleModel modelHandle = (AttributeHandleModel)model;
Model modelValue = modelHandle.Value();

[/source]


I don't think I'm quite understanding why this can't be

[source lang="csharp"]IGetter<Model> model = entity.getAttribute(FNVHash.hashString("model"));
Model modelValue = model.Value();[/source]
?

In practice, you'd probably want a more diamond-shaped tree for the handles, with both IGetter and ISetter extending some other interface, but this would allow you to do everything you've described so far.
[/quote]

But it wouldn't as what I want is a way to access my values without having to specify the type in the base class interface, the whole point is I wish to do this without making IAttributeHandle a generic class. It can have generic method functions but not a generic type as an overall whole. Maybe I am not understanding generics properly as I am seeing them as type safe templates and those allow me to write a simple access function that is templated. C++ is the language I know most about and maybe I should have mentioned that.

I fixed it differently seeing that generics can't really contain primitive types and have to be ref types, I can then cast everything to an Object and stick a fairly generic function in the base class. I don't really mind having to cast to the type I am expecting, which is what I do know in most cases and this works nicely arround the fact that a AtrributeUIModel handle is not a AttributeModelHandle.


Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!