views:

86

answers:

2

I have two questions, actually. But they are very closely related.

Suppose I have a simple struct like this:

public struct TradePrice {
    public float Price;
    public int Quantity;

    public TradePrice(float price, int quantity) {
        Price = price;
        Quantity = quantity;
    }
}

Question 1

Now if I have code somewhere that needs to access these values, is there any difference between doing this:

TradePrice tp = new TradePrice(50.0f, 100);

And this:

float p = 50.0f;
int q = 100;

I feel like the first, since it is calling a constructor, should have something like the overhead of a method call. But that is just a guess.

Question 2

The answer to the above question actually probably answers this question as well, but perhaps there is some subtlety that makes these scenarios different; so I will ask anyway. Suppose I have a struct which itself has members that are struct types. Like this:

public struct BidAsk {
    public TradePrice Bid;
    public TradePrice Ask;
}

Then would there be any difference between these three methods?

Reset(TradePrice bid, TradePrice ask) {
    Bid = bid;
    Ask = ask;
}

Reset(float bidPrice, int bidQuantity, float askPrice, int askQuantity) {
    Bid = new TradePrice(bidPrice, bidQuantity);
    Ask = new TradePrice(askPrice, askQuantity);
}

Reset(float bidPrice, int bidQuantity, float askPrice, int askQuantity) {
    Bid.Price = bidPrice;
    Bid.Quantity = bidQuantity;
    Ask.Price = askPrice;
    Ask.Quantity = askQuantity;
}

I am inclined to think that there is some overhead to the constructor for a struct, and so even though the same amount of data is being passed/set in the above methods, the first and last ones might be slightly more efficient. Is this true? And are the first and last methods even different?

For the record, I'm not asking this because I mistakenly believe this is contributing to a performance bottleneck or that it particularly matters from a design standpoint (though perhaps someone will surprise me by arguing that it does). I'm asking because I'm just curious.

+4  A: 

Passing structs instead of individual values may lead to better maintainability because if you ever need to change the struct definition the code change impact will be lower.

Otávio Décio
It will also be more readable.
Austin Salonen
+6  A: 

You've got bigger problems to sort out first. This code smells bad.

Problem #1: you're using a binary floating point number to represent a financial quantity. Binary floating point numbers are designed to represent scientific quantities where tiny errors in the last few bits of precisions are unimportant. They are extremely unsuitable for representing exact financial quantities. If you are representing financial quantities always use decimal, never use float.

Problem #2: Supposing that you had a good reason to use binary floating point, don't use float. Use double. Modern hardware is optimized to do double precision arithmetic, not single precision; there are situations in which single precision is actually slower. Of course, double takes up twice as much memory as float, but unless you've got a few million of these in memory at once, it really doesn't matter. And besides, you should be using decimal anyway, which is four times larger than float.

Problem #3: You have a mutable value type. Mutable value types are pure evil. It is so easy to accidentally cause bugs with mutable value types. Avoid avoid avoid.

Problem #4: Is that really the right name for the struct? I would think that the "trade price" would be represented by the Price property. Is there a better name for this thing that more clearly describes what it represents? Does it represent some clear concept in your business domain?

Problem #5: You do no validation on the arguments passed in to a public constructor of a public struct. This seems hazardous. What if someone tries to trade -100 shares at a price of -100000.00 a share. What happens? Nothing good, I'll bet.

Problem #6: The default value of a struct should always be a valid instance of the struct. Is it? The default instance of this struct is Price = 0, Quantity = 0. Does that actually make sense? If it doesn't, then don't make this a struct. Make it a class.

Problem #7: Is this logically a value type in the first place? Why is it a struct? Is this something that you feel should be treated logically as a value, like the number 12, or logically as something you can refer to "the same thing" in multiple locations, like a customer? If it is not logically a value, don't use a value type.

Assuming the name is correct and that this is logically a value type, your code should be something like:

public struct TradePrice 
{ 
    public decimal Price {get; private set;}
    public int Quantity {get; private set; }
    public TradePrice(decimal price, int quantity) : this()
    { 
        if (price < 0m) throw new ...
        if (quantity < 0) throw new ...
        this.Price = price; 
        this.Quantity = quantity; 
    } 
} 

As for your actual questions: there is no logical difference. There might be a performance difference. I haven't got the faintest idea of whether there is a measurable performance difference here or not. You've already writen the code both ways. Get a stopwatch, run it a billion times both ways, and then you'll know the answer to your question.

Eric Lippert