Extract Action<> and Func<>

After reading about Functional Programming, I've come to realize that I often enter this situation.

FindXinYAndDoZ(A)

-->Y.FindXAndDoZTo(A)

      -->Iterate something in Y based on A

          -->If X

              --->Do Z to X

Now, When I want to implement FindXinYAndDoWTo(A)

Then, I suddenly realize that my code above mixes the action of finding something and what to do with it once I have found it.

I should have passed Z as an Action<X> instead.

If I have this c# code:

private void FindAndDeletePersonByName(data d, string name )  // Yeah, I know linq. This is for example.

{

     foreach(person p in data.persons)

     {

          if (p.Name==name)

             p.Delete();

     }

}

As Time progresses, there are two things I may want to change while reusing the rest: Either the comparison predicate or the action of deleting.

If I select the p.Name==name and choose "Introduce variable", I am given a bool type because that is the return type of the selected expression.

But what I really want to do, is to get a Func<Bool> expressed as a lambda expression:

Func<bool> predicate = ()=>p.Name==name;

and I wish to extract "name" turning the declaration into

Func<string,bool> predicate = (theName)=> p.Name==theName;    

...so that I will be able to either extract the whole Func as a parameter, implement it as a strategy pattern or hardcode it differently in subclasses.

A prime objective of object orientation is to separate what changes from what stays the same. By making lambdas a first class citizen, I think resharper could do wonders.

4 comments
Comment actions Permalink

Hello Tormod,

Did you try selecting expression you'd like to "functionalize" and trying
to introduce parameter? It has option to create func/action.

Sincerely,
Ilya Ryzhenkov

JetBrains, Inc
http://www.jetbrains.com
"Develop with pleasure!"


TS> After reading about Functional Programming, I've come to realize
TS> that I often enter this situation.
TS>
TS> FindXinYAndDoZ(A)
TS> -->Y.FindXAndDoZTo(A)
TS> -->Iterate something in Y based on A
TS> -->If X
TS> --->Do Z to X
TS> Now, When I want to implement FindXinYAndDoWTo(A)
TS>
TS> Then, I suddenly realize that my code above mixes the action of
TS> finding something and what to do with it once I have found it.
TS>
TS> I should have passed Z as an Action Func<string,bool> predicate = (theName)=> p.Name==theName;
TS>
TS> ..so that I will be able to either extract the whole Func as a
TS> parameter, implement it as a strategy pattern or hardcode it
TS> differently in subclasses.
TS>
TS> A prime objective of object orientation is to separate what changes
TS> from what stays the same. By making lambdas a first class citizen, I
TS> think resharper could do wonders.
TS>
TS> ---
TS> Original message URL:
TS> http://devnet.jetbrains.net/message/5271988#5271988


0
Comment actions Permalink

At least I think I did.


        public void Refactoring_Test()
        {
            System.Environment.SetEnvironmentVariable("TestVariable", "TestValue");
        }

I've tried to mark the whole line and just the expression (leaving out the semicolon).

It says "return type is void".

If I use "Refactor this", then the options are introduce variable and extract method.

Can you refactor the above to a method that accepts Action as a parameter?

        public void Refactoring_Test(Action<string,string> theAction)
        {
            theAction("TestVariable", "TestValue");
        }

or even just

       public void Refactoring_Test(Action theAction)
        {
            theAction();
        }

If so, how?

0
Comment actions Permalink

I believe for void methods, no. I'll check it tomorrow.

Sincerely,
Ilya Ryzhenkov

JetBrains, Inc
http://www.jetbrains.com
"Develop with pleasure!"


IR> At least I think I did.
IR>
IR> public void Refactoring_Test()
IR> {
IR>
IR> System.Environment.SetEnvironmentVariable("TestVariable",
IR> "TestValue");
IR> }
IR> I've tried to mark the whole line and just the expression (leaving
IR> out the semicolon).
IR>
IR> It says "return type is void".
IR>
IR> If I use "Refactor this", then the options are introduce variable
IR> and extract method.
IR>
IR> Can you refactor the above to a method that accepts Action as a
IR> parameter?
IR>
IR> public void Refactoring_Test(Action<string,string>
IR> theAction)
IR> {
IR> theAction("TestVariable", "TestValue");
IR> }
IR> or even just
IR>
IR> public void Refactoring_Test(Action theAction)
IR> {
IR> theAction();
IR> }
IR> If so, how?
IR>
IR> ---
IR> Original message URL:
IR> http://devnet.jetbrains.net/message/5271995#5271995


0
Comment actions Permalink

Sound good. Looking forward to your answer.

Naturally this works:

        public void test()
        {
            int p = returnSomething();
        }

        private int returnSomething()
        {
            int n;
            if (Environment.GetEnvironmentVariable("SomeTest").Length > 0)
                n = 1;
            else
                n = 2;
            return n;
        }

Here I can extract the predicate like this

        public void test()
        {
            int p = returnSomething(Environment.GetEnvironmentVariable("SomeTest").Length > 0);
        }

        private int returnSomething(bool b)
        {
            int n;
            if (b)
                n = 1;
            else
                n = 2;
            return n;
        }

.....or I can choose to not include " > 0" in the selection, which will give an int as parameter type.

but given this:

        public void test()
        {
            int p = returnSomething();
        }

        private int returnSomething()
        {
            int n=3;
            if (Environment.GetEnvironmentVariable("SomeTest").Length + n > 0)      // NOTE that I am including n in the expression
                n = 1;
            else
                n = 2;
            return n;
        }

...then I am actually looking to extract a parameter of type Func<int,bool>

0

Please sign in to leave a comment.