0

Let's say I have some piece of code that I want to reuse. This piece of code has the property that it either returns something or that it modifies some data but does not return anything. Because of that, I cannot make it a usual method (return type void is wrong since it might return, and any return type is wrong as well since it might not return).

Does C# support that kind of "method" in any way, i.e. allows to encapsulate and reuse such a piece of code somehow?

Below is an example use case:

I have an interface ITree<T> and many classes T implementing ITree<T>.

interface ITree<T>
{
    public T Child;
    public bool Ignore;
}

I have a lot of methods that take an object of some type T implementing ITree<T> as argument and that have some class as return type. Almost all of these methods look like this:

MyClass2 SomeMethod(MyClass1 input) // MyClass1 implements ITree<MyClass1>
{
    while (input.Ignore)
    {
        input = input.Child;
        if (input == null)
            return null;
    }

    ... // do MyClass1 specific stuff and finally return some instance of MyClass2
}

Because the while loop is the same everywhere, I would like to encapsulate it in a "method", like this:

... WhileLoop<T>(ref ITree<T> input)
{ // can't specify return type because it might return null or nothing at all
    while (input.Ignore)
    {
        input = input.Child;
        if (input == null)
            return null;
    }
}

MyClass2 SomeMethod(MyClass1 input)
{
    WhileLoop(ref input);
        // either returns null or changes input so that input can be used below

    ... // do MyClass1 specific stuff and finally return some element of MyClass2
}

But since this "method" may or may not return something, it cannot be a method in the usual sense.

Rand Random
  • 7,300
  • 10
  • 40
  • 88
Kjara
  • 2,504
  • 15
  • 42
  • Why do you have to avoid returning something? Couldn't you follow the pattern established by the 'return' variation, and just not use it for the ones where you don't actually care about the return type? – Marisa Nov 21 '17 at 12:46
  • I don't have to avoid returning, I want to know if it is possible to do that in C#. – Kjara Nov 21 '17 at 12:48
  • In C#, you either never return something or always return something (even if that something is nothing/null). It would be very difficult to establish expectations for a given method if this weren't the case. Now, whether or not you use the returned value, that's up to you. – Marisa Nov 21 '17 at 12:51
  • What's the point to return anything if that is always null? What's a problem if `WhileLoop` will just return void? – Evk Nov 21 '17 at 13:11

3 Answers3

1

I might misunderstand the question, but what about returning a bool?

bool MoveToNextNonIgnoreChild<T>(ref ITree<T> input)
{
    while (input.Ignore)
    {
        input = input.Child;
        if (input == null)
            return false;
    }

    return true;
}

MyClass2 SomeMethod(MyClass1 input)
{
    if (!MoveToNextNonIgnoreChild(ref input)) return null;

    ... // do MyClass1 specific stuff and finally return some instance of MyClass2
}
C.Evenhuis
  • 25,996
  • 2
  • 58
  • 72
  • The point of my question is: I am looking for ways to avoid writing code (or equivalent code) more than once. In my example I would write the same 6 lines of code, i.e. the while loop, in every one of my methods. This is what I want to avoid. Your proposal is no better because it still forces me to write the same code (`if (MoveToNextNonIgnoreChild(ref input) { ... } else { return null; }`) in every one of my methods. – Kjara Nov 21 '17 at 14:23
  • Please do not remove your answer even if it does not answer my question. It helps to clarify what my question is all about! (That's why I gave you an upvote.) – Kjara Nov 21 '17 at 14:26
  • @Kjara I still don't understand exactly what you're _expecting_, but happy to hear my answer had at least a tiny bit of use :) – C.Evenhuis Nov 21 '17 at 14:33
  • My expectation is that I can put the while loop in some THING (not a method in usual sense, but maybe something else that I don't know of yet), so that I can replace the 6 lines of the while loop by just one line in which I call that THING. Since I must reference that THING to call it, I can do not better than one line of code - i.e. one line is the optimum. – Kjara Nov 21 '17 at 14:36
  • @Kjara I've updated my answer and cheated with the `return null` on the same line, in case you wanted a single line only for the ease of copy-pasting. C# doesn't have a "conditional return", I wouldn't know how to reduce this further. – C.Evenhuis Nov 21 '17 at 14:45
1

There is no keyword for "voidable return" of a function. C# does not support that, and I don't think any language does, since it would break encapsulation (the calling method should know what the return value would be in advance to get or not get the result). The only alternative you have are, returning null, ignoring the output of the function or making a void method that has an output parameter.

KinSlayerUY
  • 1,903
  • 17
  • 22
  • 1
    Actually, functional (or mostly-functional) languages unify all types so that what the OP asks would be possible. For example, F# has a type ``unit`` with a singleton value ``()`` that is used when a method/function returns nothing, or takes no arguments. – dumetrulo Nov 21 '17 at 14:06
  • that is just void keyword in C#, but when a method is sometimes a function? – KinSlayerUY Nov 21 '17 at 14:08
  • 1
    The difference is that you cannot create an instance of ``void`` in C#, i.e. ``void test = Console.WriteLine("test");`` is something you cannot do, whereas in F# you can perfectly write ``let test = stdout.WriteLine "test"``. — In any case, I believe this only makes a difference if you want to have a method looping to find the next non-ignore child, and then executing a continuation function that works with the value found; that will indeed be impossible in C#. – dumetrulo Nov 21 '17 at 14:29
0

If I understand your question correctly, your interface ITree<T> should actually look like this:

interface ITree<T>
{
    public ITree<T> Child;
    public bool Ignore;
}

Notwithstanding the naming issue (it is a linked list rather than a tree), the loop to find the next non-ignore child (or the original input, if Ignore is false) could look like this:

public static ITree<T> GetNextNonIgnoreChild(this ITree<T> input)
{
    while (input != null && input.Ignore) input = input.Child;
    return input;
}

Usage:

MyClass2 SomeMethod(MyClass1 input) // MyClass1 implements ITree<MyClass1>
{
    input = input.GetNextNonIgnoreChild();
    if (input == null) return null;
    ... // do MyClass1 specific stuff and finally return some instance of MyClass2
}

Honestly, written like this you actually have no significant code saving at all; you might as well write:

MyClass2 SomeMethod(MyClass1 input) // MyClass1 implements ITree<MyClass1>
{
    while (input != null && input.Ignore) input = input.Child;
    if (input == null) return null;
    ... // do MyClass1 specific stuff and finally return some instance of MyClass2
}
dumetrulo
  • 1,993
  • 9
  • 11