views:

187

answers:

6

While developing ASP.NET applications I often need to parse a boolean value given in string form, e.g. from a query string like ?visible=true

I found two solutions to implement the parsing:

bool Visible
{
    get
    {
        bool b;
        return Boolean.TryParse(this.Request["visible"], out b) && b;
    }
}

or

bool Visible
{
    get
    {
        bool b;
        return Boolean.TryParse(this.Request["visible"], out b) ? b : false;
    }
}

How do you think which way is preferred? And probably faster?

P.S. It's not a micro-opt, I just want to get know

P.P.S. I'm not familiar with IL so decided to ask here

+3  A: 

The first one is a bit nicer because it uses less code, so I would go with that.

I doubt there is much of a speed difference between the two, but if you really care you should profile both of them - run each one a million times or so and record the runtimes.

Justin Ethier
@Justin Ethier, or see what IL they generate. In either case this is micro optimization and it doesn't matter. Go with the clean code, as you suggest.
Chad
+5  A: 

I think both of them are probably functionally wrong (maybe I don't understand what you're tryinig to do), but even if they are correct, you don't care which is faster.

You really, really don't care.

MarkR
I just want to know, probably on IL level
abatishchev
@abatishchev: Then look at the IL.
Esteban Araya
+16  A: 

Don't micro optimize, make it readable.

I think this is more readable:

bool visible;
Boolean.TryParse(this.Request["visible"], out visible);
return visible;

readable variable names usually helps ;) And this implementation actually yields fewer op codes compared to the other two, and I assume it will perform in fewer cycles, being faster than both your attempts.

So, it's not only more readable imo, but also faster since it skips the if statement. The other two have equal op codes, just switched the logic around on the checking.

[Edit - compiled with Release flags - shorter IL]

If you look at the three following implementations:

public bool Visible1
{
    get 
    {
        bool b;
        return Boolean.TryParse(HttpContext.Current.Request["visible"], out b) && b;
    }
}

public bool Visible2
{
    get
    {
        bool b;
        return Boolean.TryParse(HttpContext.Current.Request["visible"], out b) ? b : false;
    }
}

public bool Visible3
{
    get
    {
        bool b;
        Boolean.TryParse(HttpContext.Current.Request["visible"], out b);
        return b;
    }
}

will yield the following IL code:

.method public hidebysig specialname instance bool get_Visible1() cil managed
{
    .maxstack 2
    .locals init (
    [0] bool b)
    L_0000: call class [System.Web]System.Web.HttpContext [System.Web]System.Web.HttpContext::get_Current()
    L_0005: callvirt instance class [System.Web]System.Web.HttpRequest [System.Web]System.Web.HttpContext::get_Request()
    L_000a: ldstr "visible"
    L_000f: callvirt instance string [System.Web]System.Web.HttpRequest::get_Item(string)
    L_0014: ldloca.s b
    L_0016: call bool [mscorlib]System.Boolean::TryParse(string, bool&)
    L_001b: brfalse.s L_001f
    L_001d: ldloc.0 
    L_001e: ret 
    L_001f: ldc.i4.0 
    L_0020: ret 
}

.method public hidebysig specialname instance bool get_Visible2() cil managed
{
    .maxstack 2
    .locals init (
    [0] bool b)
    L_0000: call class [System.Web]System.Web.HttpContext [System.Web]System.Web.HttpContext::get_Current()
    L_0005: callvirt instance class [System.Web]System.Web.HttpRequest [System.Web]System.Web.HttpContext::get_Request()
    L_000a: ldstr "visible"
    L_000f: callvirt instance string [System.Web]System.Web.HttpRequest::get_Item(string)
    L_0014: ldloca.s b
    L_0016: call bool [mscorlib]System.Boolean::TryParse(string, bool&)
    L_001b: brtrue.s L_001f
    L_001d: ldc.i4.0 
    L_001e: ret 
    L_001f: ldloc.0 
    L_0020: ret 
}

.method public hidebysig specialname instance bool get_Visible3() cil managed
{
    .maxstack 2
    .locals init (
    [0] bool b)
    L_0000: call class [System.Web]System.Web.HttpContext [System.Web]System.Web.HttpContext::get_Current()
    L_0005: callvirt instance class [System.Web]System.Web.HttpRequest [System.Web]System.Web.HttpContext::get_Request()
    L_000a: ldstr "visible"
    L_000f: callvirt instance string [System.Web]System.Web.HttpRequest::get_Item(string)
    L_0014: ldloca.s b
    L_0016: call bool [mscorlib]System.Boolean::TryParse(string, bool&)
    L_001b: pop 
    L_001c: ldloc.0 
    L_001d: ret 
}
Mikael Svenson
It's not a micro-opt, I just want to get know
abatishchev
I added il code to show
Mikael Svenson
@abatishchev: edited my answer with correct IL code. The previous was debug release and not optimized. And turns out the code I propose is also faster. Mainly due to skipping an if statement.
Mikael Svenson
+2  A: 

Actually, the other way would be

bool Visible
{
    get
    {
        bool b;
        Boolean.TryParse(this.Request["visible"], out b)
        return b;
    }
}

Since b will be set to default(bool) (false) if the TryParse fails.

And b MUST be set by TryParse because it's an out variable.

Don't micro-optimize, code so it's readable.

Chad
A: 

In this case it will not make any significant difference at all. Parsing the string takes so much longer that the small difference between the operators doesn't matter.

In a case where it would make any difference, you should profile the code to know which is actually faster. The real performance doesn't only depend on the single operator, but also what kind of operations are done before and after that point in the code.

An educated guess is that the && operator is somewhat faster. Because there is no conditional jump, it goes better with the parallel processing of consecutive operations that modern processors do.

Guffa
+2  A: 

The speed difference between the two of them would be infinitesimal compared with the cost of the page lifecycle. The main problem with them both is they are not very readable. Why don't you simply do the following:

return Request["visible"] == "true";

It achieves the same end and it is totaly clear. I cannot see any value in what you are doing it is just confusing.

Ben Robinson
`String.Equals(Request["visible"], Boolean.TrueString, StringComparison,OrdianlIgnoreCase)` probably is more correct
abatishchev
"True".Equals(value, StringComparison.OrdinalIgnoreCase)) is what TryParse actually does. Then for "False. Then it trims whitespace, and checks both strings again if necessary.
Mikael Svenson