CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 18
  1. #1
    Join Date
    Feb 2006
    Posts
    89

    Generics for numbers?

    I'm attempting to write an application which does quite a bit of math, and since speed is a real factor, I wanted to provide the end-user with a choice on how much precision they want (as a speed trade-off). So, I came up with a vector class like this:

    Code:
    public partial class Vector<T> where T : float, double, decimal
    { /* stuff */ }
    However, it gives me a strange set of errors:

    Code:
    Error	1	'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.	D:\Coding\C# Projects\Work\MyApp\Math\VectorMath.cs	23	19	MyApp
    Error	2	'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.	D:\Coding\C# Projects\Work\MyApp\Math\VectorMath.cs	23	26	MyApp
    Error	3	'decimal' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.	D:\Coding\C# Projects\Work\MyApp\Math\VectorMath.cs	23	34	MyApp
    I understand what it means, but I don't understand why there would be such a restriction on type constraints. Is there another way I should be doing this, short of three separate classes? I don't want to implement the entire program three times, and there are many numeric operations I'd need to do that couldn't be done on just a general object.

  2. #2
    Join Date
    Jul 2005
    Location
    Sydney, Australia
    Posts
    1,080

    Re: Generics for numbers?

    Quote Originally Posted by MSDN
    Types of Constraints
    Your constraint can specify the following requirements in any combination:

    The type argument must implement one or more interfaces

    The type argument must be of the type of, or inherit from, at most one class

    The type argument must expose a parameterless constructor accessible to the code that creates objects from it

    The type argument must be a reference type, or it must be a value type
    Your constraints don't meet those requirements. Perhaps it would be convenient to be able to provide a list of types that the type argument must be one of, but generics do not support that. Generics just aren't going to do what you want to do. One class with overloaded methods would do the job.
    Last edited by jmcilhinney; December 19th, 2007 at 08:58 PM.
    Tutorials: Home & Learn | Start VB.NET | Learn VB.NET | C# Station | GotDotNet | Games in VB.NET 101 Samples: 2002 | 2003 | 2005 | More .NET 2.0 (VB.NET, C#) Articles: VB.NET | C# | ASP.NET | MoreFree Components: WFC | XPCC | ElementsEx | VBPP | Mentalis | ADO.NET/MySQL | VisualStyles | Charting (NPlot, ZedGraph) | iTextSharp (PDF) | SDF (CF) ● Free Literature: VB 2005 (eBook) | VB6 to VB.NET (eBook) | MSDN Magazine (CHM format) ● Bookmarks: MSDN | WinForms .NET | ASP.NET | WinForms FAQ | WebForms FAQ | GotDotNet | Code Project | DevBuzz (CF) ● Code Converter: C#/VB.NET | VB.NET/C# | VS 2005 add-in

  3. #3
    Join Date
    Feb 2006
    Posts
    89

    Re: Generics for numbers?

    Quote Originally Posted by jmcilhinney
    Your constraints don't meet those requirements. Perhaps it would be convenient to be able to provide a list of types that the type argument must be one of, but generics do not support that.
    Yeah, I just don't see why not. It will let you specify for classes & interfaces, but not specific structs or basic data types? Gimme a break. The compiler should be able to easily enforce that kind of type safety.

    Quote Originally Posted by jmcilhinney
    Generics just aren't going to do what you want to do. One class with overloaded methods would do the job.
    It would do the job if you have huge amounts of computing power, yes. But efficiency is very high on the list of priorities for this project. It's not at all uncommon for the old, unmanaged version written in C & FORTRAN and hand-optimized to run for 10 minutes or more to do the computation. If this doesn't at least get somewhere in that ballpark, no one is going to pay it any attention. I'd probably sooner just give up on variable precision and go with double precision like the old one.

    Oh, and since this is basically the foundation of the math libraries for the project, it wouldn't be one class that would need to be overloaded, it would more than likely be dozens. If you did manage it with one class or set of classes, it would be something bizarre like implementing INumber or some ugly work-around like that.

    Though... sometimes things that should have been in the language are there, but buried in the CIL. Is there a way to modify the IL to make such a constraint on generic type parameters?

  4. #4
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Generics for numbers?

    You are thinking that generics are like templates in C++ (a common mis-conception).

    In C++ a seperate code base is actually "written" by the compiler for each set of template arguments.

    With generics it is a SINGLE codebase with all of the dirty typecasting done behind the scenes, and optimized.

    This is the reason for the restrictions, the IL has to be able to CAST AT RUNTIME whatever parameter you specialize with to the type you put in the where clause.

    Regarding performance. Remember Manage, Manage, Manage. If you have a program written even 3-5 years ago and are using hardware from that generation, then probably even the worst version you could write today would still be significantly faster.

    I have seen companies waste hundes of thousands of dollars because they "needed optimized code", when n fact the overall performance of the application has no noticible difference between an optimizzed version and a well written version (reliable, maintainable being the focus)

    btw: The application I was refering to was a gas dispersion control system for ion-beam systems running in a hi-vacuum environment with turbos and cryogenic plates. LOTS of physics, tons of math.
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  5. #5
    Join Date
    May 2007
    Posts
    1,546

    Re: Generics for numbers?

    Quote Originally Posted by TheCPUWizard
    In C++ a seperate code base is actually "written" by the compiler for each set of template arguments.

    With generics it is a SINGLE codebase with all of the dirty typecasting done behind the scenes, and optimized.
    Nope, you're thinking of Java there. Java generics are purely a compile time constraint. There exists no java bytecode for 'generic type'. In java for a List<string> type, all that happens is the compiler takes your 'generic' class, inserts the relevant casts, and uses a bog standard arraylist.

    In C# we have things a little better. Generics support is built into the runtime. In C#, if the JIT hits a generic class in your code (for example List<string>), it then checks to see if it has already compiled a List<string>, if it has not, it compiles a strongly typed class with no casts which is a List<string>. If i instantiated a List<int>, the JIT would generate a brand new class which has no casting/boxing for List<int> In java there would be both casts and boxing for value types.


    If speed is of the utmost concern, then using generics isn't the way to go. Calling a generic method is about 3-5 times slower than calling a regular method. I can't remember the exact figures at the moment. Also, calling virtual methods is slow too.

    So, if you want the ultimate in performance, you'll have to create separate classes/structs for each of your types. If you're going to be making a lot of vectors (which i assume you will), then making it a struct would probably be the way to go.

    EDIT: Also, to reiterate what TheCPUWizard said - Any project that starts out with the aim to make everything as fast as possible invariably ends up so convoluted that it's impossible to maintain. Code it in an easy to understand way first, then benchmark it to see where improvements can be made. Thats the approach i'd recommend, which has always worked for me.
    Last edited by Mutant_Fruit; December 20th, 2007 at 04:52 AM.
    www.monotorrent.com For all your .NET bittorrent needs

    NOTE: My code snippets are just snippets. They demonstrate an idea which can be adapted by you to solve your problem. They are not 100% complete and fully functional solutions equipped with error handling.

  6. #6
    Join Date
    Jul 2005
    Location
    Sydney, Australia
    Posts
    1,080

    Re: Generics for numbers?

    Quote Originally Posted by Aurrin
    Yeah, I just don't see why not. It will let you specify for classes & interfaces, but not specific structs or basic data types? Gimme a break. The compiler should be able to easily enforce that kind of type safety.
    That might seem convenient to you but that type of functionality doesn't make sense. If you specify an interface or class constraint then you're saying that every type used will either implement that interface or inherit that class. Fixing that point guarantees that your generic type will have all the members defined by that interface or class, so you can then safely access those members within the generic type definition.

    What exactly would a constraint of float, double or decimal fix? Nothing. There is no specific commonality among those types other than that they are value types, which you CAN apply a constraint for. Obviously you are interested in the fact that each of those types supports mathematical operators, but those operators are defined independently for each of those types. They are not inherited from a common source so they are not common functionality.

    Just because something may appear to be convenient to your circumstances doesn't make it logical. Anyway, if efficiency is of utmost importance then purpose-written code is always going to be more efficient. As soon as you generalise something you lose a step. Generalisation is for developer convenience, not final performance.
    Tutorials: Home & Learn | Start VB.NET | Learn VB.NET | C# Station | GotDotNet | Games in VB.NET 101 Samples: 2002 | 2003 | 2005 | More .NET 2.0 (VB.NET, C#) Articles: VB.NET | C# | ASP.NET | MoreFree Components: WFC | XPCC | ElementsEx | VBPP | Mentalis | ADO.NET/MySQL | VisualStyles | Charting (NPlot, ZedGraph) | iTextSharp (PDF) | SDF (CF) ● Free Literature: VB 2005 (eBook) | VB6 to VB.NET (eBook) | MSDN Magazine (CHM format) ● Bookmarks: MSDN | WinForms .NET | ASP.NET | WinForms FAQ | WebForms FAQ | GotDotNet | Code Project | DevBuzz (CF) ● Code Converter: C#/VB.NET | VB.NET/C# | VS 2005 add-in

  7. #7
    Join Date
    Jul 2003
    Location
    Maryland
    Posts
    762

    Re: Generics for numbers?

    It sounds to me like you may want to look into using C++ and templates. I'm not sure if you can use templates with managed C++ code but that could also solve your issue.

  8. #8
    Join Date
    Feb 2006
    Posts
    89

    Re: Generics for numbers?

    Quote Originally Posted by Mutant_Fruit
    If speed is of the utmost concern, then using generics isn't the way to go. Calling a generic method is about 3-5 times slower than calling a regular method. I can't remember the exact figures at the moment. Also, calling virtual methods is slow too.
    This is true. I'm willing to take some performance hits for the improvements that managed code and generalization will bring to it. This project is born largely out of frustration at the built-in limits (such as hard-coded array limits) and specialization of the original program. So, what I'm trying to do is find a good balance between generalized, elegant code and efficiency of calculation.

    The multiple classes really is going to make the code too complicated, and is probably unnecessary for many or most parts. I just wanted to keep the options open at this level, because this is the foundation of the rest of the program. I think what I'll do is forget float altogether and only use decimal in a few places if double overflows or is very close to zero.

    Quote Originally Posted by Mutant_Fruit
    So, if you want the ultimate in performance, you'll have to create separate classes/structs for each of your types. If you're going to be making a lot of vectors (which i assume you will), then making it a struct would probably be the way to go.
    And thanks for the struct suggestion. I'll see if I can make that work with the code I already have.

    Quote Originally Posted by Mutant_Fruit
    EDIT: Also, to reiterate what TheCPUWizard said - Any project that starts out with the aim to make everything as fast as possible invariably ends up so convoluted that it's impossible to maintain. Code it in an easy to understand way first, then benchmark it to see where improvements can be made. Thats the approach i'd recommend, which has always worked for me.
    Right. I don't want to hyper-optimize, I just want to go in with a good understanding of what effects the structure of the program will have on the efficiency so I don't end up with crap like avoidable boxing/unboxing bottlenecks and such.

    And since you mentioned it, how much of a penalty would you take for calling a list of delegates (a more elegant solution for selecting optional calculations) instead of a long if-else train that calls functions? I'll probably do the list of delegates regardless, unless that's a very steep penalty, but I am curious.

  9. #9
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Generics for numbers?

    Quote Originally Posted by Mutant_Fruit
    Nope, you're thinking of Java there. Java generics are purely a compile time constraint. There exists no java bytecode for 'generic type'. In java for a List<string> type, all that happens is the compiler takes your 'generic' class, inserts the relevant casts, and uses a bog standard arraylist.

    In C# we have things a little better. Generics support is built into the runtime. In C#, if the JIT hits a generic class in your code (for example List<string>), it then checks to see if it has already compiled a List<string>, if it has not, it compiles a strongly typed class with no casts which is a List<string>. If i instantiated a List<int>, the JIT would generate a brand new class which has no casting/boxing for List<int> In java there would be both casts and boxing for value types.


    If speed is of the utmost concern, then using generics isn't the way to go. Calling a generic method is about 3-5 times slower than calling a regular method. I can't remember the exact figures at the moment. Also, calling virtual methods is slow too.

    So, if you want the ultimate in performance, you'll have to create separate classes/structs for each of your types. If you're going to be making a lot of vectors (which i assume you will), then making it a struct would probably be the way to go.
    I was NOT thinking JAVA (but my explaination sure sounded like it )

    I did over simplify. When I was referring to "behind the scenes" it is by the JIT compiler generating unique source (without runtime casting). The (Language) compiler does just generate one set of MSIL. This means that the implementations must be identical at the MSIL level.

    You can not have different instanciations where a given operation will be a "floating point add" in one specialization, and an "integer add" in another.

    One of the things I used to do all the time in C++ was write high performance (realtime multi-channel audio processing) where I would pass different class type to templates. The implementation of a given method might be virtual for one specialization, direct for another, or even completely different (and inlined) structures.

    Since the (language) compiler generated specific code for each I could really achieve the same performance as doing #define based macro substution in 95% of the cases (without the intended headache).

    Whith Generics, you have to qualify with an Interface or Class. If the method is virtual (which it almost always is), the compiler will generate the MSIL for a virtual call. There is simply no way do get multiple MSIL implementations that are optimized taking full advantage of the knowledge available at the time the specialization is encountered.

    The JIT generation does eliminate the overhead of the casting (as you mentioned), but this comes at a price (checking if the specialization has been JITed. In many cases it can actually be faster to take the "hit" of a cast vs the "hit" of a JIT (especially if the code is called infrequently).
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  10. #10
    Join Date
    May 2007
    Posts
    1,546

    Re: Generics for numbers?

    Quote Originally Posted by TheCPUWizard
    I was NOT thinking JAVA (but my explaination sure sounded like it
    Heh, k.

    In C++ a seperate code base is actually "written" by the compiler for each set of template arguments.

    With generics it is a SINGLE codebase with all of the dirty typecasting done behind the scenes, and optimized.

    This is the reason for the restrictions, the IL has to be able to CAST AT RUNTIME whatever parameter you specialize with to the type you put in the where clause.
    It's just the above sounds like the perfect description of java generics. Java generics are a single codebase with dirty typecasting.

    With C# the JIT does create new instantiations (i.e. it writes an entirely new class) for each generic type, this way there is no type casting involved.

    this comes at a price (checking if the specialization has been JITed. In many cases it can actually be faster to take the "hit" of a cast vs the "hit" of a JIT (especially if the code is called infrequently).
    Remember, each line of code is only JITed once, so the specialisation will only ever be JITed once - the first time it is executed. So even if the code is infrequently called (a few times per application lifespan), using generics is still the better choice.
    www.monotorrent.com For all your .NET bittorrent needs

    NOTE: My code snippets are just snippets. They demonstrate an idea which can be adapted by you to solve your problem. They are not 100% complete and fully functional solutions equipped with error handling.

  11. #11
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: Generics for numbers?

    Quote Originally Posted by Mutant_Fruit
    With C# the JIT does create new instantiations (i.e. it writes an entirely new class) for each generic type, this way there is no type casting involved.
    And if you consider JIT to be behind the scenes.. In any case it is a matter of semantics, we both agree that the JIT creates new native code for each specialization.

    Remember, each line of code is only JITed once, so the specialisation will only ever be JITed once - the first time it is executed. So even if the code is infrequently called (a few times per application lifespan), using generics is still the better choice.
    Probably....but if you write a 1000 line class as a generic and there is only one typecast in an infrequesntly used portion of the code, and you have 100 specializations....

    The point I am trying to make is that there can be no way to make an ABSOLUTE statement on this. As with any performance issue, it requires measurement of the specific situation.
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  12. #12
    Join Date
    Jun 1999
    Posts
    153

    Re: Generics for numbers?

    Quote Originally Posted by Aurrin
    I'm attempting to write an application which does quite a bit of math, and since speed is a real factor, I wanted to provide the end-user with a choice on how much precision they want (as a speed trade-off). So, I came up with a vector class like this:

    Code:
    public partial class Vector<T> where T : float, double, decimal
    { /* stuff */ }
    However, it gives me a strange set of errors:
    It should be:

    Code:
    public partial class Vector<T> where T : struct
    { /* stuff */ }
    "struct" in this context denotes a value type, so it includes float, double decimal, but also int etc.
    Kevin

  13. #13
    Join Date
    May 2007
    Posts
    1,546

    Re: Generics for numbers?

    That's only marginally less useless, but still useless. 'struct' includes stuff like 'Point' and 'KeyValuePair<K, V>'. In this particular case, generics aren't useful.
    www.monotorrent.com For all your .NET bittorrent needs

    NOTE: My code snippets are just snippets. They demonstrate an idea which can be adapted by you to solve your problem. They are not 100% complete and fully functional solutions equipped with error handling.

  14. #14
    Join Date
    Feb 2006
    Posts
    89

    Re: Generics for numbers?

    Quote Originally Posted by Kevin McFarlane
    It should be:

    Code:
    public partial class Vector<T> where T : struct
    { /* stuff */ }
    "struct" in this context denotes a value type, so it includes float, double decimal, but also int etc.

    I tried that. Unfortunately, that is quite useless, as it also allows string, int, bool, etc. I needed to pare it down to things that could do floating-point math, so that when I wrote

    Code:
    T result = t1 * t2;
    The compiler could figure out that the multiplication operator would indeed work for every specified type. However, as was pointed out earlier, this is not a true commonality, and is (sadly) beyond the scope of generics.

  15. #15
    Join Date
    Feb 2006
    Posts
    89

    Re: Generics for numbers?

    Quote Originally Posted by TheCPUWizard
    And if you consider JIT to be behind the scenes.. In any case it is a matter of semantics, we both agree that the JIT creates new native code for each specialization.



    Probably....but if you write a 1000 line class as a generic and there is only one typecast in an infrequesntly used portion of the code, and you have 100 specializations....

    The point I am trying to make is that there can be no way to make an ABSOLUTE statement on this. As with any performance issue, it requires measurement of the specific situation.
    Well, if it's possible, I would like to force the JIT compiler to pre-compile the entire thing immediately on installation. I believe I read that that is possible somewhere, though it's been a while back, and with an earlier version of .NET. Then JIT would only be an issue if/when you added plug-ins.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured