If

  • Thread starter Thread starter shapper
  • Start date Start date
S

shapper

Hello,

I have the following:

if (tp.Weight >= 80) {
tp.Weight = 80;
}
else if (tp.Weight >= 60) {
tp.Weight = 60;
}
else if (tp.Weight >= 40) {
tp.Weight = 40;
}
else if (tp.Weight >= 20) {
tp.Weight = 20;
}
else {
tp.Weight = 0;
}

Is there a way to make this code shorter? Just wondering ..
Note that I always give the same value as the one I am testing ...

Thanks,
Miguel
 
How about:

static int MyFunc(int weight)
{
weight = (weight / 20) * 20;
return weight > 80 ? 80 : weight;
}

and tp.Weight = MyFunc(tp.Weight);

As in:

Console.WriteLine(MyFunc(0));
Console.WriteLine(MyFunc(5));
Console.WriteLine(MyFunc(20));
Console.WriteLine(MyFunc(25));
Console.WriteLine(MyFunc(40));
Console.WriteLine(MyFunc(45));
Console.WriteLine(MyFunc(60));
Console.WriteLine(MyFunc(65));
Console.WriteLine(MyFunc(80));
Console.WriteLine(MyFunc(85));
Console.WriteLine(MyFunc(100));
Console.WriteLine(MyFunc(105));

Marc
 
shapper said:
Hello,

I have the following:

if (tp.Weight >= 80) {
tp.Weight = 80;
}
else if (tp.Weight >= 60) {
tp.Weight = 60;
}
else if (tp.Weight >= 40) {
tp.Weight = 40;
}
else if (tp.Weight >= 20) {
tp.Weight = 20;
}
else {
tp.Weight = 0;
}

Is there a way to make this code shorter? Just wondering ..

Yes. For example:

bool SnapWeightTo(Whatever tp, int weight)
{
if (tp.Weight >= weight)
{
tp.Weight = weight;
return true;
}
return false;
}

and then:

SnapWeightTo(tp, 80) || SnapWeightTo(tp, 60) || SnapWeightTo(tp, 40) ||
SnapWeightTo(tp, 20) || SnapWeightTo(tp, 0);

though the readability of this solution is suspect.
 
Actually, as part of some functional-programming work I've been
looking at recently (investigating F#), I've also been looking at more
versatile versions of switch (to compare to the F# approach)...

"don't do this", but I have some working code that allows:

var func = new Switch<int, int>()
.Case(x => x >= 80, 80)
.Case(x => x >= 60, 60)
.Case(x => x >= 40, 40)
.Case(x => x >= 20, 20)
.Default(0);

int result = func.Evaluate(65);

the "x => x >= 80" looks slightly unnatural because of the lambda (=>)
so close to the inequality (>=) - and note that the right-hand-side
could also have been a lambda...

I'm not saying that this is a good idea, but an interesting
investigation ;-p Maybe the C# team will be inspired by the better
aspects of F# to provide more flexible pattern constructs... who
knows...

Marc
 
shapper said:
Hello,

I have the following:

if (tp.Weight >= 80) {
tp.Weight = 80;
}
else if (tp.Weight >= 60) {
tp.Weight = 60;
}
else if (tp.Weight >= 40) {
tp.Weight = 40;
}
else if (tp.Weight >= 20) {
tp.Weight = 20;
}
else {
tp.Weight = 0;
}

Is there a way to make this code shorter? Just wondering ..
Note that I always give the same value as the one I am testing ...

Thanks,
Miguel

How about:

tp.Weight %= 100;
tp.Weight -= tp.Weight % 20;
 
Marc Gravell said:
Actually, as part of some functional-programming work I've been
looking at recently (investigating F#), I've also been looking at more
versatile versions of switch (to compare to the F# approach)...

"don't do this", but I have some working code that allows:

var func = new Switch<int, int>()
.Case(x => x >= 80, 80)
.Case(x => x >= 60, 60)
.Case(x => x >= 40, 40)
.Case(x => x >= 20, 20)
.Default(0);

int result = func.Evaluate(65);

the "x => x >= 80" looks slightly unnatural because of the lambda (=>)
so close to the inequality (>=) - and note that the right-hand-side
could also have been a lambda...

I'm not saying that this is a good idea, but an interesting
investigation ;-p Maybe the C# team will be inspired by the better
aspects of F# to provide more flexible pattern constructs... who
knows...

To be honest, all we really need is a let-expression that could be used to
introduce variables within the scope of a (sub)expression. Then your example
could be written as:

var result =
let x = Foo.Bar.Baz in
x >= 80 ? 80 :
x >= 60 ? 60 :
x >= 40 ? 40 :
x >= 20 ? 20 :
0;

which is quite readable, in my opinion.

Of course, we can explicitly do what Scheme does under the hood with "let",
and desugar it into a lambda...

TResult Bind<T, TResult>(this T x, Func<T, TResult> body) { return
body(x); }

var result =
Foo.Bar.Baz.Bind(x =>
x >= 80 ? 80 :
x >= 60 ? 60 :
x >= 40 ? 40 :
x >= 20 ? 20 :
0);

But this doesn't quite look as nice, and has an obvious performance penalty.
 
To be honest, all we really need is a let-expression that could be used to
introduce variables within the scope of a (sub)expression.

Well, I'm not sure the "introduce variables" gives us anything we
don't already have; the ternary conditional approach is quite nice,
but the bracketing gets tricky if the right-hand-side of any is non-
trivial. If anything, I'd rather an extension to the ternary
conditional syntax to make this more fluent (like how null coalescing
is fluent).

Re the Bind - this is unnecessary; you can do the same just with an
inline ternary (or a static method, which would remove the need for
delegate invoke):

(here I've added the missing brackets to show the worst-case of what
it would need to support)

static int MyFunc(int x)
{
return (x >= 80) ? (80)
: ((x >= 60) ? (60)
: ((x >= 40) ? (40)
: ((x >= 20) ? (20)
: (0))));
}

Marc
 
Oh - I forgot to say; a very important factor here is that if the
*was* a new fluent-friendly ternary conditional syntax, then it would
have to be compiled *as though* it were the existing ternary syntax
(full-bracket version). Imprtantly,it should fit into the existing
Expression logic, just like concatenated ternary conditionals are -
i.e. (Northwind):

ctx.Log = Console.Out;
var qry = from order in ctx.Orders
select order.Freight >= 80 ? 20
: order.Freight >= 60 ? 60
: order.Freight >= 40 ? 40
: order.Freight >= 20 ? 20
: 0;
var data = qry.ToArray();

Goes down to the database as:

SELECT
(CASE
WHEN [t0].[Freight] >= @p0 THEN @p1
WHEN [t0].[Freight] >= @p2 THEN @p3
WHEN [t0].[Freight] >= @p4 THEN @p5
WHEN [t0].[Freight] >= @p6 THEN @p7
ELSE @p8
END) AS [value]
FROM [dbo].[Orders] AS [t0]

which is close enough ;-p

Marc
 
Marc Gravell said:
Well, I'm not sure the "introduce variables" gives us anything we
don't already have

It does, because it blurs the separation between statements and expressions
further, and allows you to do some things inline which right now have to be
split into several statements (and therefore cannot be done in the middle of
a LINQ query, for example, and has to be refactored into a method of its
own).

It's actually rather telling that LINQ itself has "let" - obviously there
are many scenarios where it's vital. Unfortunately, there are just as many
scenarios which don't involve LINQ, but which could use "let" for the same
reasons.
Re the Bind - this is unnecessary; you can do the same just with an
inline ternary (or a static method, which would remove the need for
delegate invoke):

You can do it if you already have the value of an expression bound to a
variable. The point of Bind is to take an expression, evaluate it once, bind
it to a name, and reuse that name inside some other expression several times
without the original expression being re-evaluated every time. In essence,
Bind is the precise equivalent of "let".
(here I've added the missing brackets to show the worst-case of what
it would need to support)

static int MyFunc(int x)
{
return (x >= 80) ? (80)
: ((x >= 60) ? (60)
: ((x >= 40) ? (40)
: ((x >= 20) ? (20)
: (0))));
}

Declaring a separate method for every such conditional (or indeed, any
expression that needs to reuse the value of some other expression) is very
inconvenient. That's why we have lambdas, after all...
 

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

Similar Threads


Back
Top