Newbie asks: How does one implement this pattern in C#?

  • Thread starter Thread starter Gomaw Beoyr
  • Start date Start date
G

Gomaw Beoyr

In C, I do it this way:


void f(
double *a,
double *b,
double *c
) {
if (a)
*a = cumbersome_calculation_of_a();
if (b)
*b = cumbersome_calculation_of_b();
if (c)
*c = cumbersome_calculation_of_c();
}


So what's the way to do it in C#? One of these ways, perhaps?


public void F( // But I don't particularly like this way
bool calcA,
bool calcB,
bool calcC,
out double a,
out double b,
out double c
) {
if (calcA)
a = cumbersomeCalculationOfA();
if (calcB)
b = cumbersomeCalculationOfB();
if (calcC)
c = cumbersomeCalculationOfC();
}


public void F( // And this way REALLY sucks!
ref double? a,
ref double? b,
ref double? c
) {
if (a != null)
a = cumbersomeCalculationOfA();
if (b != null)
b = cumbersomeCalculationOfB();
if (c != null)
c = cumbersomeCalculationOfC();
}



So, which is the "stardard pattern" in C# to do this?

(Please don't reply that I should make it three separate
functions and calls. The actual problems are more complex
than my examples above.)


Gomaw
 
What is really the difference between your C version and the second C#
version. Other then slight syntax issues, they look essentially the same.
Why would that not work?
 
public void F( // And this way REALLY sucks!
ref double? a,
ref double? b,
ref double? c
)

Could you tell us *why* it sucks, exactly? It's exactly equivalent to
the C version, although admittedly on the calling side you'll need a
variable of the appropriate type.
So, which is the "stardard pattern" in C# to do this?

Frankly, the standard pattern is not to do that kind of thing. I can't
remember ever running into a similar situation.
(Please don't reply that I should make it three separate
functions and calls. The actual problems are more complex
than my examples above.)

Perhaps you could give us some more information about them then,
because currently this doesn't feel like an elegant way of approaching
the problem.
 
If you're asking about C# syntax, what you have will work.

If you're asking about OOP, the code suggest the Strategy pattern.
--
Grace + Peace,
Peter N Roth
Engineering Objects International
http://engineeringobjects.com
Home of Matrix.NET
 
the simplest way to simplify this situation is :
public abstract class MyBase
{
public MyBase(double number)
{
this.number = number;
}

public abstract DoCalculation();
private double number;
public double Number
{
get{return number;}
set{number = value;}
}
}

public class ConcreteA : MyBase
{
public ConcreteA(double number) : base(number)
{
}

public override void DoCalculation()
{
//do your calculation here.
}
}

public class ConcreteB : MyBase
{
public ConcreteB(double number) : base(number)
{
}

public override void DoCalculation()
{
//do your calculation here.
}
}

public class ConcreteC : MyBase
{
public ConcreteC(double number) : base(number)
{
}

public override void DoCalculation()
{
//do your calculation here.
}
}


public class Test
{
public void Main(string[] args)
{
MyBase n1 = new ConcreteA(1);
MyBase n2 = new ConcreteB(1);
MyBase n3 = new ConcreteC(1);

Console.WriteLine(n1.DoCalculation());
Console.WriteLine(n2.DoCalculation());
Console.WriteLine(n3.DoCalculation());
}
}
 
The difference is that in the C case it's the address that
is zero (i.e. the value "doesn't exist") bit in the C# case
it't the value that is zero.

/Gomaw
 
So, which is the "stardard pattern" in C# to do this?

Frankly, the standard pattern is not to do that kind of thing. I can't
remember ever running into a similar situation.[/QUOTE]

Ok, I'll give the example in C:

void f(SomeType *x, double *a, double *b, double *c) {
double aa;

if (a || b || c)
aa = calcA(x);

if (a)
*a = aa;

if (b)
*b = calcB(x, aa);

if (c)
*x = calcC(x, aa);

}


I.e. you don't want to do more that you have to. Typically, a, b,
and c are e.g. (potential) columns in a spreadsheet that's updated
real-time. If the user chooses to see all three of them, the
systems becomes slower, because then you have to calculalte a, b,
and c. What you don't want to do, though, is to calculate a three
times.

/Gomaw

 
Gomaw Beoyr said:
Frankly, the standard pattern is not to do that kind of thing. I can't
remember ever running into a similar situation.

Ok, I'll give the example in C:[/QUOTE]

You've already given the pattern in C, pretty much. What you *hadn't*
given is the higher level problem.
I.e. you don't want to do more that you have to. Typically, a, b,
and c are e.g. (potential) columns in a spreadsheet that's updated
real-time. If the user chooses to see all three of them, the
systems becomes slower, because then you have to calculalte a, b,
and c. What you don't want to do, though, is to calculate a three
times.

Ah - now that changes things. If they're columns in a spreadsheet, I'd
make them mutable reference type objects. Pass in null if you don't
want to perform the computation, or the column if you do. Update the
column's result if you do the computation.
 
Ah - now that changes things. If they're columns in a spreadsheet, I'd
make them mutable reference type objects. Pass in null if you don't
want to perform the computation, or the column if you do. Update the
column's result if you do the computation.

They're not necessarily columns in a spreadsheet. On this
level, they are doubles. Let's say it's a function that
calculates what happens when you drop something from height
h on a planet with gravity g:


void calcDrop(double h, double g,
double *vImpact, double *vAvg, double *tFall) {
double t, vI;

if (tFall || vImpact || vAvg)
t = sqrt(2.0*h/g);

if (tFall)
*tFall = t;
if (vImpact || vAvg)
vImp = g*t;
if (vImpact)
*vImpact = vImp;
if (vAvg)
*vAvg = 0.5*vImp;
}
}

In reality, the function would be much more complex, due to
atmosphere viscosity and stuff like that, but you get the
picture.

Now, this function may be called from different places in the
system, e.g. to show the data in a spreadsheet, but also to
calculate intermediate results that other spreadsheet columns,
reports, graphs etc are based upon: You can't assume how the
data returned (i.e. duration of fall, impact speed, and average
speed) will be used.

/Gomaw
 
Gomaw Beoyr said:
They're not necessarily columns in a spreadsheet. On this
level, they are doubles.

Well, do they have to be?

With proper encapsulation, I don't think this should come up very
often. Neither should passing parameters by reference, IMO.
 
I.e. you don't want to do more that you have to. Typically, a, b,
and c are e.g. (potential) columns in a spreadsheet that's updated
real-time. If the user chooses to see all three of them, the
systems becomes slower, because then you have to calculalte a, b,
and c. What you don't want to do, though, is to calculate a three
times.

Questions:
How would this method normally be called? (simple harness that demonstrates usage)
Why one method instead of 3?
Why pass by ref instead of using a return value?:
double CalcA(double a) as opposed to
void CalcA(ref double a)

I understand the need to minimize unneeded work if it will impart performance, I don't
understand the need to pass by ref.

Bill
 
They're not necessarily columns in a spreadsheet. On this
level, they are doubles.

Well, do they have to be?

With proper encapsulation, I don't think this should come up very
often. Neither should passing parameters by reference, IMO.[/QUOTE]

You're of course correct, this doesn't happen very often. It
happens when you have some kind of time-critical calculation
where the number of required (by the calling module)
out-parameters vary from call to call.

Example (C) where f1, f2, f3, f4, f5, and f6 contains some heavy
calculations (e.g. solving differential equations numerically):


void f(double x, double y, double z
double *a, double *b, double *c, double *d) {

double aa, bb;

if (a || b || c || d) {
aa = f1(x) + f2(y) * f3(z);
if (a)
*a = aa;
if (b || c) {
bb = f4(aa, x, y, z);
if (b)
*b = bb;
if (c)
*c = f5(aa, bb, x, y, z);
}
if (d)
*d = f6(aa, x, y, z);
}
}

My original question was if there is any "standard way" i C# to
do this, e.g.:

public static void F(double x, double y, double z
bool calcA, bool calcB, bool calcC, bool calcD,
out double a, out double b,
out double c, out double d) {
//etc...
}

However, this doesn't look very nice, but perhaps it's nevertleless
the least ugly way to do it?

/Gomaw
 
Gomaw Beoyr said:
(e-mail address removed) (Jon Skeet [C# MVP]) writes:
With proper encapsulation, I don't think this should come up very
often. Neither should passing parameters by reference, IMO.

You're of course correct, this doesn't happen very often. It
happens when you have some kind of time-critical calculation
where the number of required (by the calling module)
out-parameters vary from call to call.

Example (C) where f1, f2, f3, f4, f5, and f6 contains some heavy
calculations (e.g. solving differential equations numerically):
<snip>

You have made your point about the need to only do as much work as required.
You have NOT told us WHY you need to call it this way.

Why do you need to pass a double by ref as opposed to using the return value?
Why does this need to be done in one method invocation?
How frequently does the input data change?
How frequently does it need to be displayed?
Could caching prior calculations be a source of optimization?
Once the user preferences are set (eg. a and b but not c) are they largely static?
Will you get interleaved requests from multiple sources with different preferences?

I class that encapsulates these complex calculations could be the way to go, but as you can see, I
have too many questions to offer you a reasonable design.

- If there are quite a few requests for the same data, caching is the way to go.
- If the user preferences are largely fixed (rarely change) you might go with a registration scheme
on your ComplexCalculation class.
- If you have interleaved requests with different preferences you might encapsulate the preferences
into an object that is passed in for each request. You also might group all of your replies into a
Reply object instead of passing values by ref.
- You might make the output (a,b c) properties on the ComplexCalculation class and provide and
Update(x, y, z) method.

So, once again, the passing a double by ref is most likely NOT the best way to go.
However, until you give us more details this is all speculation.

Bill
 
<snip>

You have made your point about the need to only do as much work as required.
You have NOT told us WHY you need to call it this way.

I thought that would be absolutely 100% clear from my example:


void f(double x, double y, double z // May be time-critical
double *a, double *b, double *c, double *d) {

double aa, bb;

if (a || b || c || d) {
aa = f1(x) + f2(y) * f3(z); // Takes a helluva time
if (a)
*a = aa;
if (b || c) {
bb = f4(aa, x, y, z); // Takes a helluva time
if (b)
*b = bb;
if (c)
*c = f5(aa, bb, x, y, z); // Takes a helluva time
}
if (d)
*d = f6(aa, x, y, z); // Takes a helluva time
}
}


All I wanted to know was what you do in C# where you in C would
pass a an adress (i.e. a pointer) as NULL because the parameter
isn't needed by the calling function.

So is there any "standard way" in C# or not? (I'm getting the
impression there isn't any.)

/Gomaw
 
Gomaw Beoyr said:
I thought that would be absolutely 100% clear from my example:

What we have here.....is a failure to communicate.

// THIS is the part I am questioning
//-------------------------------------------------------------------
void f(double x, double y, double z, double *a, double *b, double *c, double *d)
//-------------------------------------------------------------------

{
//This part I understand
//Lots of time consuming stuff
}

I assume that you call it something like this:
double xx = 3.14;
double yy = 1.414;
double zz = 6.0;
double aa;
double bb;
double cc;
double dd;

void Blah()
{
f(xx, yy, zz, &aa, &bb, &cc, &dd);
// or
f(xx, yy, zz, &aa, null, &cc, null);
}


WHY do it this way as opposed to this ? (or something similar)
Results f(double x, double y, double z) // a,b c,d are values in the Result class

void Blah()
{
Result result = f(xx, yy, zz);
aa = result.A
bb = result.B
...
}


I am *NOT* questioning your need to optimize.
I *AM* questioning your need to pass doubles by ref
*THEN* we can discuss HOW best to achieve this
All I wanted to know was what you do in C# where you in C would
pass a an adress (i.e. a pointer) as NULL because the parameter
isn't needed by the calling function.

If you passed in an object instead of a value type this would work fine.
I haven't played with Nullable types in 2.0 yet, but they might fit the bill.

So is there any "standard way" in C# or not? (I'm getting the
impression there isn't any.)

The *Standard* way is to get away from the C mindset of using pointers unless you really need to.

Why do you need to mess with addresses/pointers?
I haven't seen anything that indicates a *NEED* for pointers.

Bill
 
I assume that you call it something like this:
double xx = 3.14;
double yy = 1.414;
double zz = 6.0;
double aa;
double bb;
double cc;
double dd;

void Blah()
{
f(xx, yy, zz, &aa, &bb, &cc, &dd);
// or
f(xx, yy, zz, &aa, null, &cc, null);
}


WHY do it this way as opposed to this ? (or something similar)
Results f(double x, double y, double z) // a,b c,d are values in the Result class

void Blah()
{
Result result = f(xx, yy, zz);
aa = result.A
bb = result.B
...
}

Because then f would calculate A _and_ B even if only A (or only B)
is required by the caller. I thought that would be 100% clear from
my example.
The *Standard* way is to get away from the C mindset of using
pointers unless you really need to.

Yes, and that's exactly why I need something else than pointer == NULL
to represent the supression of the calculation of the corresponding
"out" variable.
Why do you need to mess with addresses/pointers?
I haven't seen anything that indicates a *NEED* for pointers.

I don't want to use pointers. In C, you do it with pointers (i.e.
"ref" is sent as a pointer) and that makes it possible to use the
value NULL to say "I don't need this particulaur output this time".

In C#, there are no pointers, so I have to say "I don't need this
particulaur output this time" in some other way. I don't know,
however, if there is any "standard other way" to do this in C#, so
that's why I asked you people in the first place.

However, I'm getting the feeling there is no standard way, so I
will probably have to use this (in my opinion rather ugly) pattern:

public void F(double x, double y, double z,
bool calcA, bool calcB, bool calcB, bool calcD,
out double a, out double b, out double c, out double d)
...

That is, unless someone suggests a more appealing way to do it.


And I also just realized that by using overloads, it won't be THAT ugly,
just a little bit ugly:

// Calculate all four
public void F(double x, double y, double z,
out double a, out double b, out double c, out double d) {
F(x, y, z,
true, true, true, true,
out a, out b, out c, out d);
}

// Calculate only a, this is a fairly common case
public void F(double x, double y, double z,
out double a) {
double dummy1, dummy2, dummy3;
F(x, y, z, true, false, false, false,
out a, out dummy1, out dummy2, out dummy3);
}
public double FA(double x, double y, double z) {
double a, dummy1, dummy2, dummy3;
F(x, y, z, true, false, false, false,
out a, out dummy1, out dummy2, out dummy3);
return a;
}


// Calculates any combination, the "ugly case"
public void F(double x, double y, double z,
bool calcA, bool calcB, bool calcB, bool calcD,
out double a, out double b, out double c, out double d) {
// Do the work here
}

The obvious drawback being that anyone using the last one would
have to declare and use dummy variables the way I do in the second
and third one... (A NULL would have been more convenient.)

Is there no "null reference" or anything like that one could use?

/Gomaw
 
----- Original Message -----
From: "Gomaw Beoyr" <[email protected]>
Newsgroups: microsoft.public.dotnet.languages.csharp
Sent: Friday, November 04, 2005 6:52 PM
Subject: Re: Newbie asks: How does one implement this pattern in C#?


Because then f would calculate A _and_ B even if only A (or only B)
is required by the caller. . I thought that would be 100% clear from
my example.

Well, since the ONLY reason(as far as you've said) you are calling it this
way is to Minimize unneeded work, I suggest that your design could be
improved and get away from the ref doubles.

Simple example
Create a Request class that wraps a,b,c, and which outputs you need
Create a Reply class that wraps x,y,z...

then
Request request = new request(a,b,....);
Reply reply = complexCalc.F(request);
//pull out the fields that you wanted

In ComplexCalc it looks like this

class ComplexCalc
{
...
// Only calculate what you need
Reply F(Request request)
{
if (request.NeedsX)
Blah();
if (request.NeedsY)
Bar();
...
Reply reply = new Reply(x,y.....);
return (reply);
}
...
}

This is one of MANY ways to go.
You could cache requests/replies incase the data is the same on consecutive
requests.
You could use a registration scheme to save your preferences IN the
ComplexCalc object.

My point is.
If you don't HAVE to use ref double.....don't
There are many cleaner ways to attack the problem.

Bill
 
Well, since the ONLY reason(as far as you've said) you are calling it this
way is to Minimize unneeded work, I suggest that your design could be
improved and get away from the ref doubles.

Simple example
Create a Request class that wraps a,b,c, and which outputs you need
Create a Reply class that wraps x,y,z...

I thank you for your efforts, but all I wanted to know was if
there is any standard way in C# to do what you do in C when you
send the adderss of (i.e. pointer) to an out-variable as NULL,
to indicate that the value isn't needed by the caller.

That's all.

/Gomaw
 
Gomaw Beoyr said:
I thank you for your efforts, but all I wanted to know was if
there is any standard way in C# to do what you do in C when you
send the adderss of (i.e. pointer) to an out-variable as NULL,
to indicate that the value isn't needed by the caller.

That's all.

OK, I'll let it drop.
Have you investigated nullable types in 2.0 yet?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top