Are there any official ways to write an Immediately Invoked Function Expression?
Asked Answered
F

7

27

Something like this:

var myObject = new MyClass()
{
    x = " ".Select(y =>
    {
        //Do stuff..
        if (2 + 2 == 5)
            return "I like cookies";
        else if (2 + 2 == 3)
            return "I like muffins";
        //More conditions...
        else
            return "I'm a bitter old man";
    })
};

I realize Select is not intended to be used this way. But yeah, what are some other ways to do the same thing?

Freeway answered 16/8, 2013 at 18:3 Comment(10)
If it's too long, put it in a function?Turro
what are some other ways to do the same thing? What are you trying to do? Where is the property?Tumefaction
I wouldn't use return in a select statement for a start (Plus basic mathematics states you are a bitter old man)Mcguigan
It's for argument's sake.Freeway
@Mcguigan I said as much in the question. I'm trying to find a proper equivalent to it.Freeway
You may get away with using a ternary operator but I don't like encouraging bad code condition1 ? "cookies" : condition2 ? "muffins" : "bitter"Mcguigan
@Mcguigan a ternary operator is exactly what I was trying to avoid xDFreeway
You should be avoiding it altogether, a collection of bitter old men has no relevance to the original collectionMcguigan
Note that your Select() code won't actually work.Shuntwound
Did you forget .Single()? Actually, this is almost idiomatic and better than what I was originally thinking of.Skimmer
M
24

I'm surprised no one's mentioned this yet, but you could use the Lazy<T> class:

var myObject = new MyClass()
{
    x = new Lazy<string>(() =>
    {
        //Do stuff..
        if (2 + 2 == 5)
            return "I like cookies";
        else if (2 + 2 == 3)
            return "I like muffins";
        //More conditions...
        else
            return "I'm a bitter old man";
    }).Value // <-- Evaluate the function here
};

Alternatively, if you want to avoid having to specify the return type anywhere (as you do with new Lazy<string> because constructors do not support type inference), you can implement a simple generic method like this:

public static T Eval<T>(Func<T> func)
{
    return func();
}

And then you can call like this:

var myObject = new MyClass()
{
    x = Eval(() =>
    {
        //Do stuff..
        if (2 + 2 == 5)
            return "I like cookies";
        else if (2 + 2 == 3)
            return "I like muffins";
        //More conditions...
        else
            return "I'm a bitter old man";
    })
};

Update: C#7 introduces local functions. These are not really IFFEs, but they may solve a variety of related issues. For example:

var myObject = new MyClass()
{
    x = GetX()
};

string GetX() {
    //Do stuff..
    if (2 + 2 == 5)
        return "I like cookies";
    else if (2 + 2 == 3)
        return "I like muffins";
    //More conditions...
    else
        return "I'm a bitter old man";
}

The key here is that GetX can be declared within the same method as myObject share the same scope as it.

Maneater answered 17/8, 2013 at 2:0 Comment(1)
This is perfect. It makes sense, it doesn't have a messy amount of parenthesizes and there is no casting going on in there.Freeway
N
28

For real code make it a function... For entertainment purposes C# equivalent of JavaScript IIFE is more direct than Select:

var myObject = new MyClass()
{
   x =((Func<int>)(() => {return 2;}))(),...
Negrophobe answered 16/8, 2013 at 18:12 Comment(4)
I just used this for populating some test data.Amerson
you can use new to make it look a little nicer. x = new Func<int>(() => 2)(). It just unfortunately can't be implicitly typed.Maas
actually you could make it implicitly typed with a static method. x = Func.Create(() => 2)();Maas
the above comment Func.Create is not built by default in dotnet. Have to refer @DaveCousineau 's other answer: https://mcmap.net/q/497101/-are-there-any-official-ways-to-write-an-immediately-invoked-function-expressionOctaviooctavius
M
24

I'm surprised no one's mentioned this yet, but you could use the Lazy<T> class:

var myObject = new MyClass()
{
    x = new Lazy<string>(() =>
    {
        //Do stuff..
        if (2 + 2 == 5)
            return "I like cookies";
        else if (2 + 2 == 3)
            return "I like muffins";
        //More conditions...
        else
            return "I'm a bitter old man";
    }).Value // <-- Evaluate the function here
};

Alternatively, if you want to avoid having to specify the return type anywhere (as you do with new Lazy<string> because constructors do not support type inference), you can implement a simple generic method like this:

public static T Eval<T>(Func<T> func)
{
    return func();
}

And then you can call like this:

var myObject = new MyClass()
{
    x = Eval(() =>
    {
        //Do stuff..
        if (2 + 2 == 5)
            return "I like cookies";
        else if (2 + 2 == 3)
            return "I like muffins";
        //More conditions...
        else
            return "I'm a bitter old man";
    })
};

Update: C#7 introduces local functions. These are not really IFFEs, but they may solve a variety of related issues. For example:

var myObject = new MyClass()
{
    x = GetX()
};

string GetX() {
    //Do stuff..
    if (2 + 2 == 5)
        return "I like cookies";
    else if (2 + 2 == 3)
        return "I like muffins";
    //More conditions...
    else
        return "I'm a bitter old man";
}

The key here is that GetX can be declared within the same method as myObject share the same scope as it.

Maneater answered 17/8, 2013 at 2:0 Comment(1)
This is perfect. It makes sense, it doesn't have a messy amount of parenthesizes and there is no casting going on in there.Freeway
F
6

Here is what my coworker came up with:

var myObject = new { 
    x = new Func<int>(() => {return 2;})() 
};

Note that this is based Alexei's answer.

Freeway answered 16/8, 2013 at 18:24 Comment(6)
@DanielGimenez it does compile. I just ran it on LinqPad. It also does what it's supposed to do.Freeway
It compiles and runs on my machine, on both LinqPad and visual studio. Yes, this is based on Alexi's answer.Freeway
Okay. I see my mistake, you had string in your original post, but you changed it to an int here.Launch
Much more concise than ((Func<int>)(() => 2))()!Skimmer
@Skimmer How do you mean "more concise"? If anything, it's more code and therefore more verbose, no?Teutonism
@Teutonism I think of it as less busy because it has fewer parentheses to keep track of. That makes it more readable to me. Checking back, I guess that the four parentheses saved matches the four characters lost by requiring new . So new Func<int>(() => 2)() and ((Func<int>)(() => 2))() are both exactly 24 characters long. I still think that new syntax is clearer than the syntax which uses two additional pairs of parentheses.Skimmer
M
5

It's can be tricky to get an implicitly typed delegate, but it works if you write your own static methods for it.

You can create an implicitly typed function like this:

public static class Func {
   public static Func<T> Create<T>(
      Func<T> func
   ) =>
     func;       
}

...

var x = Func.Create(() => "result")();
Assert.AreEqual("result", x);

var x = Func.Create(() => {
   // complex logic to create a value
})();

And you can also write one to immediately evaluate a function and then you don't need to do it manually:

public static class Func {
   public static T Eval<T>(
      Func<T> func
   ) =>
      func();
}

...

var x = Func.Eval(() => 5);
Assert.AreEqual(5, x);
Maas answered 29/9, 2018 at 20:52 Comment(6)
exactly, and you can add multiple overloads with different count of generic argumentsMagness
This is IMO the cleanest option. Note that you could execute the delegate within the Create method, and save the extra parentheses. I usually name this method IIFE, and do precisely that; I reference it with using static so the call ends up looking like this: IIFE(() => /* produce value here */);.Obscure
@IvanSanz-Carasa The point of an IIFE is to return a single value without any parameters -- "immediately executing function expression. There isn't really any need for multiple overloads.Obscure
@ZevSpitz in Func<...Args, TOut>, the first type parameters are used as input arguments so overloads will be ok when your function accepts parameters. For example: Func.Create((int x, int y) => x + y)(myVar1, myVar2) it would require you to define this overload: public static Func<TOut> Create<T0, T1, TOut>(Func<T0,T1,TOut> pFunc) => pFuncMagness
@IvanSanz-Carasa But you could simply use the variables inside the body of the function: IIFE(() => myVar1 + myVar2), because you're invoking it right away. What do you gain by having an immediately invoked function that you have to pass parameters into?Obscure
in the IIFE case nothing, but when creating a function that is reusable yesMagness
R
4

While certainly not "official", you could use optional named parameters in the constructor or a separate factory/builder method:

public class MyClass
{
   public string x { get; private set; }

   public MyClass(Func<string> x = null)
    {
        if (x != null)
            this.x = x();
    }
}

with usage like:

var myClass = new MyClass(
        x: () =>
            {
                //Do stuff..
                if (2 + 2 == 5)
                    return "I like cookies";
                else if (2 + 2 == 3)
                    return "I like muffins";
                //More conditions...
                else
                    return "I'm a bitter old man";
            }
    );

    Console.WriteLine(myClass.x); //"I'm a bitter old man"

So, it's not the exact syntax you were asking for, but pretty close and skips the LINQ weirdness.

That said, I don't like it. Just offering it as food for thought. :)


EDIT: I figured I'd add a factory method style since it's plausible you're using this on a class that you can't (or don't want to) change its constructor:

public static class MyFactory
{
    public static MyClass CreateMyClass(Func<string> x = null)
    {
        var myClass = new MyClass()

        if (x != null)
                myClass.x = x();

        return myClass;
    }
}

With similar usage (just calling a factory method instead):

var myClass = MyFactory.CreateMyClass(
    x: () =>
        {
            //Do stuff..
            if (2 + 2 == 5)
                return "I like cookies";
            else if (2 + 2 == 3)
                return "I like muffins";
            //More conditions...
            else
                return "I'm a bitter old man";
        }
);

EDIT: And hey, while we're at it. Why not go off the deep end and do it with a separate builder and abuse implicit operators!

public class MyClassBuilder
{
    public Func<string> x { get; set; }

    public static implicit operator MyClass(MyClassBuilder builder)
    {
        var myClass = new MyClass();

        if (builder.x != null)
            myClass.x = builder.x();

        return myClass;
    }
}

With usage like:

MyClass myClass = new MyClassBuilder
{
    x = () =>
        {
            //Do stuff..
            if (2 + 2 == 5)
                return "I like cookies";
            else if (2 + 2 == 3)
                return "I like muffins";
            //More conditions...
            else
                return "I'm a bitter old man";
        }
};

So now the syntax is identical, except you have to explicitly type your instance instead of using var.

Richma answered 16/8, 2013 at 18:17 Comment(1)
While the first example is interesting it isn't what the asker wanted. The second example is the cleanest I've seen, and gets the point.Launch
B
1

Maybe not quite answering the question but ... one reason I wanted IIFE in C# was to give better meaning to a function being called on an object. In this example I wanted to give meaning as to what the 'Click' method does in a particular context within test code (and I do not like comments).

Before ...

lastLine.Click(); //click to begin editing line

After ...

Action<IWebElement> clickToStartEditing = line => line.Click();
clickToStartEditing(lastLine);

Later I discovered I could simply create a new method with another name ...

Action clickToStartEditing = lastLine.Click;
clickToStartEditing(lastLine);

Finally simply naming the variable in a better way can better solve the issue (for me)

lastLineForEditing.Click();

This solved an IIFE issue for me, to give meaning to the method name.

Buckshee answered 22/8, 2018 at 10:54 Comment(0)
P
0

You can do:

global using static System.IIFE;

namespace System {
  public static class IIFE {
    public static T Scope<T>(Func<T> f) => f();
  }
}

And then:

var x = Scope(() => {
  var t1 = getVal();
  vat t2 = getVal2();
  return t1+t2;
});

The advantage of IIFE here is that t1 and t2 do not pollute the outside scope

Pierson answered 9/8, 2023 at 7:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.