Something[void]
От: artelk  
Дата: 01.12.11 16:22
Оценка:
А нельзя ли как-нибудь малой кровью добавить возможность параметризовать генерики типом void, раз уж даже такие вещи можно делать:
  mutable x : void = ();
  x = WriteLine("Hi");

?

Когда это может понадобится:
  //Выполнение кода в каком-то контексте
  ExecInContext[T](f : SomeContext -> T) : T
  {
    using(def ctx = SomeContext())
      f(ctx);
  }

Так вот, передать в ExecInContext функцию SomeContext->void нельзя.
Придется явно делать перегрузку:
  //Так, с копипастом
  ExecInContext(f : SomeContext -> void) : void
  {
    using(def ctx = SomeContext())
      f(ctx);
  }

  //Или как-нибудь так
  ExecInContext(f : SomeContext -> void) : void
  {
    _ = ExecInContext(ctx => { f(ctx); null : object; });
  }


Или, например, вместо void использовать везде FakeVoid из computation expressions.

Так вот, нельзя ли автоматизировать все это?
Например, добавить структуру
public struct VoidStruct
{
  public static Value : VoidStruct = VoidStruct();
}

И научить компилятор делать замены в коде.
Т.е., например:
ExecInContext(_ => {/*...*/});//если тело лямбды имеет тип void
ExecInContext.[VoidStruct](_ => {/*...*/; VoidStruct.Value; });//заменять так


Для случая генериков с указанием "where T:class" использовать класс VoidClass:
public abstract class VoidClass
{
  public static Value : VoidClass = null;
  private this() {}
}

ExecInContext_Class[T](f : SomeContext -> T) : T
      where T : class
{
  using(def ctx = SomeContext())
    f(ctx);
}

ExecInContext_Class(_ => {/*...*/});//если тело лямбды имеет тип void
ExecInContext_Class.[VoidClass](_ => {/*...*/; VoidClass.Value;});//заменять так


Есть проблема, если в качестве параметра f передается не лямбда, создаваемая по месту, а, например, некая уже существующая функция T->void:
module Test
{
  F(ctx : SomeContext) : void { /*...*/ }
}

ExecInContext(F);
//придется заменять на
ExecInContext(ctx => {F(ctx); VoidStruct.Value; });

Или:
def f : SomeContext->void = ctx => {/*...*/};
//тут какой-то код, для которого требуется, чтобы f была с типом SomeContext->void
ExecInContext(f);//тоже придется оборачивать


В этом случае создается новый объект и передается в качестве параметра.
В случае делегатов это может привести, например, к невозможности отписки от событий.

Нет ли возможности как-то решить эту проблему?

PS На правах размышлений вслух.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.