Monday, October 09, 2017

The end of Windows Mobile/Phone just leaves more questions

With posts like this, it seems that Microsoft is starting to publicly acknowledge the end for Windows Phone/Mobile.

So should we just shut up and move on?
It's not that clear-cut. There are still some things to consider.

If you've built Phone/Win10Mobile apps that doesn't mean you should abandon them. If you still have users keep serving them while it makes sense to do so.

Windows isn't dead.
It's part of three areas that cover the broad spectrum of computing that Microsoft support.

There's Azure for Web/Cloud
There's Xamarin for X-Platform Mobile development
There's UWP for everything else (PC, Gaming, IOT, & more)


This still leaves lots of questions/thinking points.

Questions specific to the Windows app ecosystem

  • What, exactly, does "not the focus" mean?
  • Will anything be done to push the consumer focus of UWP apps?
  • Will the mobile version of Windows 10 ever go away?
  • What about small tablets? Will they ever be a thing? And, if so what version of Win10 would they run?
  • What about Windows on ARM?
  • Will we see greater investment and support for UWP and Xamarin? So there's a single solution for client apps on all platforms?

Broader questions

  • Is it good that there are only 2 mobile platforms (iOS & Android) out there?
  • Are there other mobile platforms that could make a challenge or drive innovation?
  • How important are devices other than the portable computers we carry in our pockets?
  • Will anything ever come of "continuum" style devices where a mobile can become a PC or it becomes your personal, portable storage, and identity?
  • Will people ever get over the silver bullet idea of "write once, run everywhere" (with no specialist knowledge or extra effort required)?
  • When will offline web support be good enough we can all just use the web all the time?
  • How will Microsoft's push for AR/VR/MR with dedicated devices sit with so many other platforms building solutions on top of mobile?
  • Does any of this really matter?


One of the joys of technology is that there are always more questions.....

Thursday, October 05, 2017

Optimizing the comparison of a variable with multiple options in C#


Yesterday, I wrote about my thoughts around optimising the comparison of a variable with multiple options and how I prefer to optimize for readability over theoretical or potential performance issues.
After some discussion on twitter about how my sample code might be optimized I thought it was worth doing some proper analysis.

The big potential optimizations are

  • The removal of LINQ
  • Not creating a new array for each check
  • Removing the need for boxing

Using BenchmarkDotNet I was able to quickly run some comparisons to see which method would be the quickest. I tried a number of variations with the type of object and array creation.

The results.

                               Method |        Mean |     Error |    StdDev |
------------------------------------- |------------:|----------:|----------:|
                       MultipleEquals |   0.0013 ns | 0.0041 ns | 0.0034 ns |
                        IsOneOfObject | 132.7228 ns | 2.2074 ns | 2.0648 ns |
       IsOneOfObjectWithExistingArray |  93.5959 ns | 1.7975 ns | 1.8459 ns |
                       IsOneOfGeneric |  63.4804 ns | 0.8762 ns | 0.7317 ns |
      IsOneOfGenericWithExistingArray |  58.5615 ns | 0.8739 ns | 0.7747 ns |
                        IsOneOfMyEnum |  64.2691 ns | 1.3435 ns | 1.3195 ns |
       IsOneOfMyEnumWithExistingArray |  58.2238 ns | 0.9457 ns | 0.8383 ns |
                  IsOneOfMyEnumNoLinq |  12.1887 ns | 0.2395 ns | 0.2123 ns |
 IsOneOfMyEnumNoLinqWithExistingArray |   6.2302 ns | 0.0519 ns | 0.0433 ns |

Full benchmark code is at https://gist.github.com/mrlacey/1b3eef0a9945b67883486bb9540b533d

While using multiple equality checks was by far the fastest approach, by removing LINQ, not boxing, and not creating a new array for each test I was able to achieve the best performance.


Conclusion
While using multiple equality checks is by far the fastest, I still think writing
if (MyEnum.Value1 || someVariable == MyEnum.Value2 || someVariable == MyEnum.Value3 || someVariable == MyEnum.Value6)
{
    /// do something
}
is far less preferable to
if (someVariable.IsOneOf[MyEnumNoLinq](targetValues))
{
    /// do something
}

And the code can still be pretty darn fast.
You just might need a few overloads to get the best performance from all comparisons.

Disclaimer.
Yes, I am aware that:

  • I only ran the tests with enums and you might get different results with different types.
  • It might not be possible to have a fixed array to compare with each time.
  • There may be further optimizations available. This is good enough for me though.
  • Based on the speeds involved this does feel like a micro-optimization unless you really are making such calls many, many times in quick succession.
  • I haven't looked at memory usage. If you're interested, go ahead, but standard warnings about premature micro-optimizations exist.

*** UPDATE ***

Ok, I gave in and looked at the memory profiling too:

                               Method |  Gen 0 | Allocated |
------------------------------------- |-------:|----------:|
                       MultipleEquals |      - |       0 B |
                        IsOneOfObject | 0.0558 |      88 B |
       IsOneOfObjectWithExistingArray | 0.0178 |      28 B |
                       IsOneOfGeneric | 0.0178 |      28 B |
      IsOneOfGenericWithExistingArray |      - |       0 B |
                        IsOneOfMyEnum | 0.0178 |      28 B |
       IsOneOfMyEnumWithExistingArray |      - |       0 B |
                  IsOneOfMyEnumNoLinq | 0.0178 |      28 B |
 IsOneOfMyEnumNoLinqWithExistingArray |      - |       0 B |


Yeah, I think it's safe to say that it's not an issue. If you're really concerned over 28 (or even 88) bytes you're in a really constrained environment and nothing I have to say about optimization or readability will be relevant or new to you. In fact, if you're in such a constrained environment you're probably best not writing in a managed language.


Wednesday, October 04, 2017

Comparing a variable with multiple options in C#

In a code review recently there was some debate about how to compare a variable with multiple values.
I'm writing this to put all my thoughts on the subject into one place and in a coherent (hopefully) manner.

As an example, consider this `if` statement.

if (new[] { MyEnum.Value1, MyEnum.Value2 }.Contains(someVariable))

It's the equivalent of "if (X or Y) = Z".

Also, consider this variation

if (someVariable == MyEnum.Value1 || someVariable == MyEnum.Value2)

The repetition of the variable typically makes it longer than the version using the array and reads, IMO, less naturally. It's the equivalent of "if (X = Y) or (X = Z)".

People tend to prefer the second option.

The argument against the first option basically comes down to:
I know an array of 2 doesn't add too much memory but it's just good practice.
I'm not convinced about the "good practice" argument.

  • Yes, an array is created, but it's tiny and there's nothing keeping it around and so can be collected as soon as is necessary.
  • It's not "common practice" I'll admit, but I've never seen code guidelines that explicitly say anything about how to do multiple comparisons. Is the first option considered wrong as it's not seen as frequently as the second?
  • It feels like a premature optimization. The argument of don't create anything that uses memory unless you need to puts preserving memory consumption above all else. I don't think that's right or something that anyone making the above argument sticks too rigidly.
If someone was really concerned about performance, I'd expect them to point out that the array method can cause boxing and this is likely to have more impact on performance than array creation. For a one-off check though the impact is still so small as to not be noticeable. This makes me think the above argument comes from a convention and perception that "creating arrays is bad" and should be avoided.


I also prefer the first option as it makes it easier to add another option. The adding of an item to a list is simpler than another comparison. As the variable needs to be compared with more options lines get very long if using direct comparisons.  Both options get longer but this gets much longer faster.
This isn't great.

if (someVariable == MyEnum.Value1 || someVariable == MyEnum.Value2 || someVariable == MyEnum.Value3 || someVariable == MyEnum.Value4 || someVariable == MyEnum.Value5)

I prefer a solution that uses an array rather than multiple explicit comparisons because I follow this maxim in my code:

Readability of code is more important than performance unless performance is an issue.

IMO, reading multiple comparison statements is harder.

In my own code, I don't actually do the above. I wrap it in a call to an extension method so it's even shorter and, IMO, reads even more naturally,

if (someVariable.IsOneOf(MyEnum.Value1MyEnum.Value2))

This reads like "if X = (Y or Z)" which is closest to spoken English.
It's also easy to add options to.


The extension method, if you're interested, is really simple.

public static bool IsOneOf(this object item, params object[] options)
{
    return options.Contains(item);
}


Some potential questions.

What if calling this type of code enough times that there is a performance impact?
- Then do what's necessary to improve performance. That's what the clause in my maxim is for.

What about not using an if statement?
- It might be more appropriate to use a `select` statement. However, if the `if` statement doesn't have an `else` clause then this leads to a `select` statement with only a single match which feels odd to me. (As above though, this may be just because I'm not used to seeing code like that.)

What about starting with direct comparisons if there are only two options and then switch to the "IsOneOf" methods when multiple comparisons are made?
- You could go that way but I'm not a fan as it becomes hard to enforce a consistent style across a codebase. It also means that the change to add functionality unnecessarily requires changing the structure of code which can make it harder to identify the meaningful differences in the change.


Thoughts?


follow up post on optimizations for the above.