Omer van Kloeten's .NET Zen

Programming is life, the rest is mere details

News

Note: This blog has moved to omervk.wordpress.com.

Omer van Kloeten's Facebook profile

Omer has been professionally developing applications over the past 8 years, both at the IDF’s IT corps and later at the Sela Technology Center, but has had the programming bug ever since he can remember himself.
As a senior developer at NuConomy, a leading web analytics and advertising startup, he leads a wide range of technologies for its flagship products.

Get Firefox


powered by Dapper 

.NET Resources

Articles :: CodeDom

Articles :: nGineer

Culture

Projects

July 2006 - Posts

Lambda Expressions, Anonymous Methods and Methods
I really think Krzysztof and friends should post some guidelines in the spirit of The Framework Design Guidelines (read: The Book You Must Read) for lambda expressions, anonymous methods and methods, so there won't be any mixup as to what should be used. I'd hate to see people start writing long anonymous method in the middle of their code - they really disturb the flow.

My suggestion:
  • Do use a lambda expression if it consists of only one expression. This is what they're there for.
  • Avoid using a lambda expression if the types of parameters and return value are not obvious.
  • Do use an anonymous method if it consists of between 1 and 4 lines of code.
  • Consider a method instead if an anonymous method if it looks unreadable in the context of the code around it.
  • Do Not use an anonymous method if the code contained in it needs to be re-used.
And also:
  • Do match the names of parameters from the delegate's declaration when declaring them in a lambda expression or an anonymous method.
Again, this is my opinion and the principles I try to follow in my code. I'd love to hear your ideas too.

I'd also love to see a refactoring feature in Orcas that lets you refactor between lambda expressions, anonymous methods and methods.
Hierarchical Linq Queries
After reading Bill Wagner's excellent introduction to Linq, I really liked what I saw and decided that I wanted to create an extension method as an exercise. I sat and thought what I would have wanted from Linq and decided I wanted to write a method that lets you select hierarchical data.

Here's a mockup of how a query would look like:
from   node in tree.ByHierarchy<HierarchicalData>(startWith, connectBy)
select node;
Each 'node' in the query will be an object holding the original item, its level of depth in the hierarchy and its parent (for convenience's sake):
public class Node<T>
{
    public int Level;
    public Node<T> Parent;
    public T Item;
}
This node will be used to determine what the item is and where it's located.
Let's take an example:
Tree t7 = new Tree { Value = 7 };
Tree t6 = new Tree { Value = 6 };
Tree t5 = new Tree { Value = 5, Left = t6, Right = t7 };
Tree t4 = new Tree { Value = 4 };
Tree t3 = new Tree { Value = 3 };
Tree t2 = new Tree { Value = 2, Left = t3, Right = t4 };
Tree t1 = new Tree { Value = 1, Left = t2, Right = t5 };
 
Tree[] treeNodes = new Tree[] { t1, t2, t3, t4, t5, t6, t7 };
 
var nodes = from   node in treeNodes.ByHierarchy<Tree>(
                               t => t == t1,
                               (parent, child) => (parent.Left == child) ||
                                                  (parent.Right == child))
            select node;
 
foreach (LinqExtensions.Node<Tree> n in nodes)
{
    for (int i = 0; i < n.Level; i++) Console.Write(' ');
 
    Console.WriteLine("Node {0}, child of {1}.",
                      n.Item.Value,
                      (n.Parent != null ? n.Parent.Item.Value.ToString() : "no one"));
}
This example will walk on the tree (which so happens to be a three-tiered complete binary tree) and print it in the order of hierarchy:
Node 1, child of no one.
Node 2, child of 1.
Node 3, child of 2.
Node 4, child of 2.
Node 5, child of 1.
Node 6, child of 5.
Node 7, child of 5.
And here's the code that does this:
using System;
using System.Collections.Generic;
using System.Query;

namespace DotNetZen.Linq
{
    public static partial class LinqExtensions
    {
        public class Node<T>
        {
            internal Node()
            {
            }
 
            public int Level;
            public Node<T> Parent;
            public T Item;
        }
 
        public static IEnumerable<Node<T>> ByHierarchy<T>(
            this IEnumerable<T> source,
            Func<T, bool> startWith,
            Func<T, T, bool> connectBy)
        {
            return source.ByHierarchy<T>(startWith, connectBy, null);
        }

        
        private static IEnumerable<Node<T>> ByHierarchy<T>(
            this IEnumerable<T> source,
            Func<T, bool> startWith,
            Func<T, T, bool> connectBy,
            Node<T> parent)
        {
            int level = (parent == null ? 0 : parent.Level + 1);
 
            if (source == null)
                throw new ArgumentNullException("source");
 
            if (startWith == null)
                throw new ArgumentNullException("startWith");
 
            if (connectBy == null)
                throw new ArgumentNullException("connectBy");
 
            foreach (T value in from   item in source
                                where  startWith(item)
                                select item)
            {
                Node<T> newNode = new Node<T> { Level = level, Parent = parent, Item = value };
 
                yield return newNode;
 
                foreach (Node<T> subNode in source.ByHierarchy<T>(possibleSub => connectBy(value, possibleSub),
                                            connectBy, newNode))
                {
                    yield return subNode;
                }
            }
        }
    }
}
Portability of Customizable and/or Adaptive User Interfaces
This March my workplace issued employees a Motorola i760 cell phone, which apart from being pretty sluggish, doesn't work the same way as my personal phone, a Nokia 3100 - the menus aren't the same, shortcuts are different, and so on. What I discovered a few minutes after receiving the phone was that the User Interface was customizable, which didn't cause the phone to suck less, but only to work the same way as my Nokia did.

Customizable and adaptive user interfaces are great, but they're not something every developer does on their own accord. Most of the time, it's "My way or the highway" when a developer designs a user interface, and since most companies don't hire designers to design their user interfaces, this might turn into a fiasco, as many of you know or have heard about.
As with my phone, Customizable User Interfaces are interfaces that allow users to change parts of themselves using a special menu or screen chuck-full of options. Adaptive User Interfaces are interfaces that change over time in accordance with how the user interacts with them, such as Windows's Start Menu (when items you don't usually click on are hidden until you click the little arrows at the bottom).

A few days after changing the entire layout on my new phone, a coworker tried to use my phone, but due to the fact that my interface had been customized one way and his another and the fact that the phone presented little to no textual or graphical cues as to which button does what (unless manually activated through, guess what, one of those unlabeled buttons), he was unable to do anything like he was used to, got pissed off and had to ask me how to do operate the phone.

What this means is that these types of user interfaces don't work well simply because they're not portable. When I sit on my own computer, logged in under my own username, I have no problem with the user interface - it is as I have set it. On the other hand, when I move to a different computer or even log on as a different user on the same machine, my customization is inexistent and sometimes even worse - the customization is for a different person, with their own preferences. This is a disorienting experience for most users and will usually take them more time to perform any action, as easy as it may be, which contradicts with the reason for creating such complex user interface logic in the first place.
This pretty annoying problem doesn't (or I should say shouldn't) happen in web applications, but it does in windows applications, where to date I've only seen one solution. You too may have seen it yourself - it's the "Save my preferences to file" method, which you can find in Microsoft Office and Visual Studio, to name only two applications, but the problem with that is that you have to carry that file with you or place it somewhere where you could access it from any computer you may use.

So what can be done about this? In my opinion, the best way the problem could be solved would be to create a central server that would save these preferences (and optionally also all other configuration changes made by the user) to some database and while your application loads, it would connect to said server and download the preferences from it, depending on which user is logged into it. This, of course, does not necessitate the creation of a logon screen in your application, which would be annoying, but rather a special form that would be filled with a their own predefined username and password. Once these credentials are entered for the first time or changed, via a form that will always be accessible from the same location (you may call it the user's 'anchor' in an unknown UI), the server would be queried for the preferences and the application would transform into what the user is already familiar with.

One might argue that this solution poses a security risk, as anyone getting hold of this 'valuable' information could do malicious things with it, but this risk is also present in the current form, where the database is not centralized, but each user has their own 'configuration file' saved on their own machine. Add this to the fact that the information could be held almost anonymously and behind very powerful encryption and you have a very low security risk (I would never say there are no security issues what-so-ever as much as I will never say an application is bug-free).

This solution looks not only applicable for vendors - holding their own repository for their applications, but there may even be a few service providers that could provide a central repository for many applications by many software vendors. Payment for this service could be an agreed upon sum per-license sold (or it could even be free (as in beer)).
Three Lines About Lambda Expressions
myObject.ITakeACharReturningDelegate(delegate(int i, string s) { return s[i]; });
myObject.ITakeACharReturningDelegate((i, s) => s[i]);
Both are the same. That's it, in a nutshell...
[Update: The HTML was malformed in the post. Sorry about that.]
Posted: Jul 07 2006, 05:09 PM by Omer van Kloeten
Filed under: , ,
More Posts