digitalmars.D.learn - Check the class of objects
- Mael (5/5) Jun 05 2008 Hello,
- Urban Hafner (9/10) Jun 05 2008 I think you should have each class report it's "class". This way it's
- janderson (26/53) Jun 05 2008 I don't like either approaches. RTTI should be looked at with a
- janderson (9/39) Jun 05 2008 BTW: let me clarify what I mean by polymorphism. I'm not talking about
- Mael (2/3) Jun 05 2008 Yes, it's obviously linked, but the question is : since each time you wa...
- Steven Schveighoffer (17/31) Jun 05 2008 The correct way is to use the if(cast(ColorByteImage)img) if you have a
- Mael (28/28) Jun 05 2008 Well, most of the time, the check won't occur a big penalty, because, fi...
- Steven Schveighoffer (15/43) Jun 05 2008 Static if can only inspect compile-time objects. This will not look up ...
- Mael (2/10) Jun 05 2008 Well, actually the point is that the action "do something" is consistent...
- Chris Wright (2/12) Jun 06 2008 Why not use the Visitor pattern?
- janderson (5/22) Jun 06 2008 This may be a good idea, however I wonder how you'd construct visitor
- janderson (35/47) Jun 06 2008 I still think you should do this instead:
- janderson (24/92) Jun 06 2008 Oh the other piece of the puzzle in your case since your doing the same
Hello, another newb question ! I'm trying to design a large image library, that should be usable enough for students to learn it quickly, but powerful enough to be used in medium-sized projects Since I'm building several image classes (depending on the characteristics of the image, such as grey / color, byte / float, etc), I can either include a flag in each image that tells its class ("I'm a color-byte image", "I'm a grey-byte image", etc.), or use many if( cast(ColorByteImage)img !is null ) { doactionColorByte ; } to check the type. What would be the most efficient way to test the type of the class ? How is the cast(Class)v construct implemented in the compiler (I guess there's some equivalent of a "i'm a color-byte image" flag in the class structure) ? Another question for people designing graphic libraries : would you recommend to pad image rows on 32-bits ? I hardly see when this is useful in practice (usually it's done for efficiency reasons, but I don't see how this would improve speed significantly, except if you're trying to extract a couple of lines of an image...). The only advantage I see is that it permits to make fast 'ImageViews' of a subset of an Image without having to duplicate it. Maybe some webcams give padded output, and it would therefore be faster to have them output directly in the image ? Someone sees the main reason (I might be missing some thing here?)
Jun 05 2008
Mael wrote:Since I'm building several image classes (depending on the characteristics of the image, such as grey / color, byte / float, etc), I can either include a flag in each image that tells its class ("I'm a color-byte image", "I'm a grey-byte image", etc.), or use many if( cast(ColorByteImage)img !is null ) { doactionColorByte ; } to check the type. What would be the most efficient way to test the type of the class ? How is the cast(Class)v construct implemented in the compiler (I guess there's some equivalent of a "i'm a color-byte image" flag in the class structure) ?I think you should have each class report it's "class". This way it's easy to add new subclass to your Image class. If you do it in the Image class (your second idea) you would have to change the Image class every time you add a new subclass! This is (IMHO) bad design as the parent class should only contain stuff that's the same for all subclasses. After all, if that's not the case, what's the point of having subclasses at all? Urban
Jun 05 2008
Mael wrote:Hello, another newb question ! I'm trying to design a large image library, that should be usable enough for students to learn it quickly, but powerful enough to be used in medium-sized projects Since I'm building several image classes (depending on the characteristics of the image, such as grey / color, byte / float, etc), I can either include a flag in each image that tells its class ("I'm a color-byte image", "I'm a grey-byte image", etc.), or use many if( cast(ColorByteImage)img !is null ) { doactionColorByte ; } to check the type. What would be the most efficient way to test the type of the class ? How is the cast(Class)v construct implemented in the compiler (I guess there's some equivalent of a "i'm a color-byte image" flag in the class structure) ?I don't like either approaches. RTTI should be looked at with a suspicions eye in my opinion (ie has its uses but the this is not one of them). Efficiency wise, dynamic casts can be slow depending on how the compiler implements them it may need to traverse each item in the tree. So the deeper the tree (another thing you should avoid) the worse the performance. enum/flag compares are pretty efficient (as long as they aren't strings). Polymorphism's bread and butter is this type of problem. Virtual lookups aren't that much worse when compared to enum flag. Its 2 memory lookups and 1 jump. Look at the surrounding code around the virtual, how much work is that doing comparatively? Probably a whole lot more. I wouldn't prematurely optimize this sort of thing.Another question for people designing graphic libraries : would you recommend to pad image rows on 32-bits ? I hardly see when this is useful in practice (usually it's done for efficiency reasons, but I don't see how this would improve speed significantly, except if you're trying to extract a couple of lines of an image...). The only advantage I see is that it permits to make fast 'ImageViews' of a subset of an Image without having to duplicate it. Maybe some webcams give padded output, and it would therefore be faster to have them output directly in the image ? Someone sees the main reason (I might be missing some thing here?)I'm not exactly sure what sort of padding your talking about so I'll take a stab at what I think you mean. I think you more or less say this but I'll clarify it a bit. Its important because of how data is aligned. If the data is not aligned the compiler will have to do extra work to realign the data before it can do work on it. Or alternatively the software will work on each byte individually rather then working on the whole 32-bits at once (or even several 32-bits at the same time). That's of course on a 32-bit machine, on a 64-bit machine you might want to align to 64-bits in some cases. It can make a big difference to performance since there are 1000s X 1000s of pixels in an image. I hope that was helpful. -Joel
Jun 05 2008
janderson wrote:Mael wrote:BTW: let me clarify what I mean by polymorphism. I'm not talking about the class return from a function its type like bool isGray(); That's almost RTTI. No, what I mean is moving the code that does stuff on isGray() into the image class, if it makes sense. Note, depending on what your doing it may be better to use a flag, or "is function" instead of polymorphism but I'd need an example. -JoelHello, another newb question ! I'm trying to design a large image library, that should be usable enough for students to learn it quickly, but powerful enough to be used in medium-sized projects Since I'm building several image classes (depending on the characteristics of the image, such as grey / color, byte / float, etc), I can either include a flag in each image that tells its class ("I'm a color-byte image", "I'm a grey-byte image", etc.), or use many if( cast(ColorByteImage)img !is null ) { doactionColorByte ; } to check the type. What would be the most efficient way to test the type of the class ? How is the cast(Class)v construct implemented in the compiler (I guess there's some equivalent of a "i'm a color-byte image" flag in the class structure) ?I don't like either approaches. RTTI should be looked at with a suspicions eye in my opinion (ie has its uses but the this is not one of them). Efficiency wise, dynamic casts can be slow depending on how the compiler implements them it may need to traverse each item in the tree. So the deeper the tree (another thing you should avoid) the worse the performance. enum/flag compares are pretty efficient (as long as they aren't strings). Polymorphism's bread and butter is this type of problem. Virtual lookups aren't that much worse when compared to enum flag. Its 2 memory lookups and 1 jump. Look at the surrounding code around the virtual, how much work is that doing comparatively? Probably a whole lot more. I wouldn't prematurely optimize this sort of thing.
Jun 05 2008
Its important because of how data is aligned. If the data is notYes, it's obviously linked, but the question is : since each time you want to process an RGB triple in the middle of any row, it won't be necessarily aligned, I don't clearly see where do you save processing time when doing for instance a constant addition to an image ? I guess there must be reasons linked to image viewing (like screens that like to have their data padded), but I could not find precise references on this
Jun 05 2008
"Mael" wroteHello, another newb question ! I'm trying to design a large image library, that should be usable enough for students to learn it quickly, but powerful enough to be used in medium-sized projects Since I'm building several image classes (depending on the characteristics of the image, such as grey / color, byte / float, etc), I can either include a flag in each image that tells its class ("I'm a color-byte image", "I'm a grey-byte image", etc.), or use many if( cast(ColorByteImage)img !is null ) { doactionColorByte ; } to check the type. What would be the most efficient way to test the type of the class ? How is the cast(Class)v construct implemented in the compiler (I guess there's some equivalent of a "i'm a color-byte image" flag in the class structure) ?The correct way is to use the if(cast(ColorByteImage)img) if you have a single attribute you want to switch on. This is implemented in the compiler as a check to make sure the class is of the valid type, and then return the casted value if it is correct, or return null if it is not. You can also get information about the most derived class at runtime using the .classinfo property, but if you have a deep hierarchy, it is less code to just do the cast test. If you want to switch on multiple orthogonal attributes, it would be better to provide properties in the class that indicate which ones are which. For example, the properties grey/color and byte/float could be orthogonal producing 4 different variations. If you only care if an image is grey or color, it would be inefficient to do something like: if(cast(ColorByteImage)img !is null || cast(ColorFloatImage)img !is null) if you could just do: if(img.isColor) -Steve
Jun 05 2008
Well, most of the time, the check won't occur a big penalty, because, first the image hierarchy will be small, and second, the pattern of use will be like : algorithmprocess(Type)(args) { static switch(Type) dostuff ; } algorithm(args) { if( isByteImage(img) ) algorithmprocess(ByteImage)(cast(ByteImage)img) ; ... } which is a bit ugly but should work.. except I can't make it work : I did something like _myalgo( T )( T u ) { static if (T == ByteImage) { do something ; } else static if( T == FloatImage) { ..; } } myalgo( Image u ) { if( isByteImage(u) ) _myalgo( ByteImage )(cast(ByteImage)u) ; ... } and I obtain something like Error: cannot evaluate opEquals(cast(Object)(ByteImage)) at compile time (refering to the line "static if( T == ByteImage ) .." someone knows what is the correct way to check for the arg types? sorry to ask newb question ..
Jun 05 2008
"Mael" wroteWell, most of the time, the check won't occur a big penalty, because, first the image hierarchy will be small, and second, the pattern of use will be like : algorithmprocess(Type)(args) { static switch(Type) dostuff ; } algorithm(args) { if( isByteImage(img) ) algorithmprocess(ByteImage)(cast(ByteImage)img) ; ... } which is a bit ugly but should work.. except I can't make it work : I did something like _myalgo( T )( T u ) { static if (T == ByteImage) { do something ; } else static if( T == FloatImage) { ..; } } myalgo( Image u ) { if( isByteImage(u) ) _myalgo( ByteImage )(cast(ByteImage)u) ; ... } and I obtain something like Error: cannot evaluate opEquals(cast(Object)(ByteImage)) at compile time (refering to the line "static if( T == ByteImage ) .." someone knows what is the correct way to check for the arg types?Static if can only inspect compile-time objects. This will not look up the derived type. If you did want static if to work, you need to use an is expression. Something like: static if(is(T == ByteImage)) But you are unnecessarily distributing your code, adding unnecessary templates, making it harder to understand/maintain What's wrong with: if(isByteImage(u)) { do something; } ... Either way, you still need the if-else block to determine what the image is at runtime. -Steve
Jun 05 2008
What's wrong with: if(isByteImage(u)) { do something; } ... Either way, you still need the if-else block to determine what the image is at runtime.Well, actually the point is that the action "do something" is consistent accross images except when trying to access data (compare bytes/floats/value/triples), and using a run time if inside the loops would be unefficient, that's why I want to only use static if in the loop, but still share most of the code since it's truly redundant
Jun 05 2008
Mael wrote:Why not use the Visitor pattern?What's wrong with: if(isByteImage(u)) { do something; } ... Either way, you still need the if-else block to determine what the image is at runtime.Well, actually the point is that the action "do something" is consistent accross images except when trying to access data (compare bytes/floats/value/triples), and using a run time if inside the loops would be unefficient, that's why I want to only use static if in the loop, but still share most of the code since it's truly redundant
Jun 06 2008
Chris Wright wrote:Mael wrote:This may be a good idea, however I wonder how you'd construct visitor that does the right conversion since you can't have virtual template inheritance. I guess you could write up a function for each version. -JoelWhy not use the Visitor pattern?What's wrong with: if(isByteImage(u)) { do something; } ... Either way, you still need the if-else block to determine what the image is at runtime.Well, actually the point is that the action "do something" is consistent accross images except when trying to access data (compare bytes/floats/value/triples), and using a run time if inside the loops would be unefficient, that's why I want to only use static if in the loop, but still share most of the code since it's truly redundant
Jun 06 2008
Mael wrote:I still think you should do this instead: interface Image { void DoSomething1(); } class ByteImage : Image { override void DoSomething1() { //do something; } } class ByteImage : Image { override void DoSomething1() { //do something else; } } ... Use case Image image = new ByteImage(); ... image.DoSomething(); Using a switch statement like you have is very poor design in my book. The great thing about doing it this way is you have no coupling to a switch statement. Someone wants to create a new type of Image they can just by inheriting from your interface. They don't need to update a whole heap of switch statements (which they may not even have access to if you used a lib.) Its becomes more like a plug-in architecture. Sorry to come across as harsh here but if your going to show this to students you should show them the right way to do such stuff. This is called the adapter pattern BTW. Wiiiiiiiiiiiiiiiiiii, -JoelWhat's wrong with: if(isByteImage(u)) { do something; } ... Either way, you still need the if-else block to determine what the image is at runtime.Well, actually the point is that the action "do something" is consistent accross images except when trying to access data (compare bytes/floats/value/triples), and using a run time if inside the loops would be unefficient, that's why I want to only use static if in the loop, but still share most of the code since it's truly redundant
Jun 06 2008
janderson wrote:Mael wrote:Oh the other piece of the puzzle in your case since your doing the same thing for each case is a template. void DoStuffTemplate(T)(T obj) { //Do nasty stuff to obj (no cast required since is the given type) } class ByteImage : Image { override void DoSomething1() { DoStuffTemplate(this); //Note, can't be in base class } } class ByteImage : Image { override void DoSomething1() { DoStuffTemplate(this); //Note, can't be in base class } } Also if you need to special case something you have 2 options, template spealization or changing the contents of DoSomething1(). -JoelI still think you should do this instead: interface Image { void DoSomething1(); } class ByteImage : Image { override void DoSomething1() { //do something; } } class ByteImage : Image { override void DoSomething1() { //do something else; } } ... Use case Image image = new ByteImage(); ... image.DoSomething(); Using a switch statement like you have is very poor design in my book. The great thing about doing it this way is you have no coupling to a switch statement. Someone wants to create a new type of Image they can just by inheriting from your interface. They don't need to update a whole heap of switch statements (which they may not even have access to if you used a lib.) Its becomes more like a plug-in architecture. Sorry to come across as harsh here but if your going to show this to students you should show them the right way to do such stuff. This is called the adapter pattern BTW. Wiiiiiiiiiiiiiiiiiii, -JoelWhat's wrong with: if(isByteImage(u)) { do something; } ... Either way, you still need the if-else block to determine what the image is at runtime.Well, actually the point is that the action "do something" is consistent accross images except when trying to access data (compare bytes/floats/value/triples), and using a run time if inside the loops would be unefficient, that's why I want to only use static if in the loop, but still share most of the code since it's truly redundant
Jun 06 2008
Actually, this wouldn't be the right solution, because the doSomething action is specific to a particular algorithm, and there will be tens of such algorithms, and I don't want to clutter the main class with parts of algorithms adapted to each class...
Jun 07 2008
mael wrote:Actually, this wouldn't be the right solution, because the doSomething action is specific to a particular algorithm, and there will be tens of such algorithms, and I don't want to clutter the main class with parts of algorithms adapted to each class...http://c2.com/cgi/wiki?ReplaceConditionalWithPolymorphism http://c2.com/cgi/wiki?SwitchStatementsSmell The following is an excerpt from Scott Meyers’ new book, Effective C++, Third Edition: 55 Specific Ways to Improve Your Programs and Designs. "Effective C++, Third Edition Item 27 7 One thing you definitely want to avoid is designs that involve cascading dynamic_casts, i.e., anything that looks like this: class Window { ... }; ... // derived classes are defined here typedef std::vector<std::tr1::shared_ptr<Window> > VPW; VPW winPtrs; ... for (VPW::iterator iter = winPtrs.begin(); iter != winPtrs.end(); ++iter) { if (SpecialWindow1 *psw1 = dynamic_cast<SpecialWindow1*>(iter->get())) { ... } else if (SpecialWindow2 *psw2 = dynamic_cast<SpecialWindow2*>(iter->get())) { ... } else if (SpecialWindow3 *psw3 = dynamic_cast<SpecialWindow3*>(iter->get())) { ... } ... } Such C++ generates code that’s big and slow, plus it’s brittle, because every time the Window class hierarchy changes, all such code has to be examined to see if it needs to be updated. (For example, if a new derived class gets added, a new conditional branch probably needs to be added to the above cascade.) Code that looks like this should almost always be replaced with" I think that only becomes appropriate if you use a template or operator overloads to generate this so its generic, less brittle and without evil down casting. -Joel
Jun 07 2008
janderson wrote:mael wrote:Sorry part of that got cut off. It says something like "replaced with virtual functions".Actually, this wouldn't be the right solution, because the doSomething action is specific to a particular algorithm, and there will be tens of such algorithms, and I don't want to clutter the main class with parts of algorithms adapted to each class...http://c2.com/cgi/wiki?ReplaceConditionalWithPolymorphism http://c2.com/cgi/wiki?SwitchStatementsSmell The following is an excerpt from Scott Meyers’ new book, Effective C++, Third Edition: 55 Specific Ways to Improve Your Programs and Designs. "Effective C++, Third Edition Item 27 7 One thing you definitely want to avoid is designs that involve cascading dynamic_casts, i.e., anything that looks like this: class Window { ... }; ... // derived classes are defined here typedef std::vector<std::tr1::shared_ptr<Window> > VPW; VPW winPtrs; ... for (VPW::iterator iter = winPtrs.begin(); iter != winPtrs.end(); ++iter) { if (SpecialWindow1 *psw1 = dynamic_cast<SpecialWindow1*>(iter->get())) { ... } else if (SpecialWindow2 *psw2 = dynamic_cast<SpecialWindow2*>(iter->get())) { ... } else if (SpecialWindow3 *psw3 = dynamic_cast<SpecialWindow3*>(iter->get())) { ... } ... } Such C++ generates code that’s big and slow, plus it’s brittle, because every time the Window class hierarchy changes, all such code has to be examined to see if it needs to be updated. (For example, if a new derived class gets added, a new conditional branch probably needs to be added to the above cascade.) Code that looks like this should almost always be replaced with"I think that only becomes appropriate if you use a template or operator overloads to generate this so its generic, less brittle and without evil down casting. -Joel
Jun 07 2008