Довольно часто встречаются задачи, в которых фигурирует некоторое значение, но при некоторых условиях значение отсутствует. Для таких ситуаций предлагается использовать конструкцию OptionalValue, см. код ниже. Код каждого метода очень простой, поэтому лучше посмотреть сам код. Ниже буду описывать использование OptionalValue.
Катастрофа при Extract Method
Рассмотрим строчку кода:
string someMethodResult = new SomeClass1().SomeMethod1();
string someMethodResult = ExtractedMethod1().SomeMethod1(); //ошибка в run time-е
SomeClass1 ExtractedMethod1()
{
return null;
}
Хочется иметь такую технику кодирования, чтобы Extract Method не переводил ошибки компиляции в ошибки run time-а.
Отсюда вывод: не использовать null в качестве возвращаемого значения! То есть набирать на клавиатуре null только: для передачи значений в уже имеющиеся методы (например, третий аргумент в методе PropertyInfo.SetValue),
в операторе сравнения (фактически вариант а),
может что-то забыл . Но не для возврата значения.
Все null-ы мы таким образом не истребим, поскольку field-ы классов инициализируются null-ами,
оператор "as" возвращает null,
уже имеющиеся библиотеки поставляют null-ы.
Но наша цель более скромная – уменьшить количество null-ов. Кстати, по пунктам a и b еще можно кое-что отвоевать.
Как будет выглядеть приведенный выше пример в случае использования OptionalValue?
Делаем замену вызова конструктора "new SomeClass1()" на Nothing. Добиваемся, чтобы код компилировался, в итоге получаем первый вариант:
string someMethodResult = OptionalValue.Nothing<SomeClass1>().Process(
value => value.SomeMethod1(),
() => "[Экземпляр класса SomeClass1 не существует]");
второй вариант:
string someMethodResult = ExtractedMethod1().Process(
value => value.SomeMethod1(),
() => "[Экземпляр класса SomeClass1 не существует]");
IOptionalValue<SomeClass1> ExtractedMethod1()
{
return OptionalValue.Nothing<SomeClass1>();
}
Таким образом, оба варианта ведут себя одинаково -- если код компилируется, то он работает.
Схожесть с System.Nullable
Да, OptionalValue очень похож на System.Nullable. Отличия: OptionalValue работает и для reference и для value типов, System.Nullable только для value типов,
у OptionalValue generic параметр ковариантный.
The Maybe Monad
Да, OptionalValue является Maybe монадой. Но использование двух перегруженных методов ProcessValue часто оказывается удобнее использования разноименных монадных методов SelectMany и Select.
Query comprehension syntax
Методы SelectMany и Select позволяют использовать query comprehension syntax для OptionalValue.
Интересные ссылки на эту тему
Изобретатель null reference называет свое изобретение ошибкой на миллион долларов:
Общественность уже понимает необходимость разделения nullable типов и не nullable типов. Но пока в майнстримовых языка/платформах это не реализовано.
A more elegant solution that will never come true is to apply value type syntax for reference types: all references are implicitly not nulls for the compiler, but a question mark after a type (ie: «string?» or «Customer?») allows you to set null to the variable. http://codevanced.net/post/One-Annotations-Way-Resharper.aspx
1.0 Non-Null Types Many errors in modern programs manifest themselves as null-dereference errors, suggesting the importance of a programming language providing the ability to discriminate between expressions that may evaluate to null and those that are sure not to (for some experimental evidence, see [24, 22]). In fact, we would like to eradicate all null dereference errors. http://stackoverflow.com/questions/1943465/avoiding-null-reference-exceptions
Методы GetValue/HasValue можно поменять местами с методом интерфеса IOptionalValue.Process, т.е. GetValue/HasValue будут в интерфейсе, а Process будет extension методом, который будет выражаться через GetValue/HasValue. В этом случае GetValue можно сделать свойством Value. Я этого не делаю, вот по какой причине. Не хочется иметь в базовом интерфейсе свойство, кидающее исключение. Метод GetValue желательно дергать как можно реже.
public interface IOptionalValue<out TValue>
{
TResult Process<TResult>(Func<TValue, TResult> existFunc, Func<TResult> notExistFunc);
}
public static class OptionalValue
{
public static IOptionalValue<TValue> Nothing<TValue>()
{
return NotExistOptionalValue<TValue>.Instance;
}
public static IOptionalValue<TValue> AsOptionalValue<TValue>(
this TValue value)
{
return new ExistOptionalValue<TValue>(value);
}
public static IOptionalValue<TTarget> ProcessValue<TValue, TTarget>(
this IOptionalValue<TValue> optionalValue,
Func<TValue, TTarget> func)
{
return optionalValue.ProcessValue(value => func(value).AsOptionalValue());
}
public static IOptionalValue<TTarget> ProcessValue<TValue, TTarget>(
this IOptionalValue<TValue> optionalValue,
Func<TValue, IOptionalValue<TTarget>> func)
{
return optionalValue.Process(func, Nothing<TTarget>);
}
public static void Process<TValue>(
this IOptionalValue<TValue> optionalValue,
Action<TValue> existAction,
Action notExistAction)
{
optionalValue.Process(existAction.ToFunc(), notExistAction.ToFunc());
}
public static void ProcessValue<TValue>(
this IOptionalValue<TValue> optionalValue,
Action<TValue> existAction)
{
Process(optionalValue, existAction, () => { });
}
public static IOptionalValue<TTarget> Select<TValue, TTarget>(
this IOptionalValue<TValue> optionalValue,
Func<TValue, TTarget> func)
{
return optionalValue.ProcessValue(func);
}
public static IOptionalValue<TTarget> SelectMany<TValue, TTarget>(
this IOptionalValue<TValue> optionalValue,
Func<TValue, IOptionalValue<TTarget>> func)
{
return optionalValue.ProcessValue(func);
}
public static IOptionalValue<T2> SelectMany<TValue, T1, T2>(
this IOptionalValue<TValue> optionalValue,
Func<TValue, IOptionalValue<T1>> func1,
Func<TValue, T1, T2> func2)
{
return optionalValue.SelectMany(
value => func1(value).Select(
value1 => func2(value, value1)
)
);
}
public static bool HasValue<TValue>(
this IOptionalValue<TValue> optionalValue)
{
return optionalValue.Process(delegate { return true; }, () => false);
}
public static TValue GetValue<TValue>(
this IOptionalValue<TValue> optionalValue)
{
return optionalValue.Process(
value => value,
() =>
{
throw new InvalidOperationException(
string.Format("Optional value of '{0}' type has no value.", typeof (TValue)));
}
);
}
public static TValue GetValueOrDefault<TValue>(
this IOptionalValue<TValue> optionalValue)
{
return optionalValue.Process(value => value, () => default(TValue));
}
public static IOptionalValue<TValue> ToOptionalValue<TValue>(
this TValue value) where TValue : class
{
return value == null ? Nothing<TValue>() : value.AsOptionalValue();
}
private class NotExistOptionalValue<TValue> : IOptionalValue<TValue>
{
public static readonly IOptionalValue<TValue> Instance = new NotExistOptionalValue<TValue>();
private NotExistOptionalValue()
{
}
public TResult Process<TResult>(
Func<TValue, TResult> existFunc, Func<TResult> notExistFunc)
{
return notExistFunc();
}
}
private class ExistOptionalValue<TValue> : IOptionalValue<TValue>
{
private readonly TValue value;
public ExistOptionalValue(TValue value)
{
this.value = value;
}
public TResult Process<TResult>(
Func<TValue, TResult> existFunc, Func<TResult> notExistFunc)
{
return existFunc(value);
}
}
}
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Довольно часто встречаются задачи, в которых фигурирует некоторое значение, но при некоторых условиях значение отсутствует. Для таких ситуаций предлагается использовать конструкцию OptionalValue, см. код ниже. Код каждого метода очень простой, поэтому лучше посмотреть сам код. Ниже буду описывать использование OptionalValue.
Это случайно не Null Object Pattern называется?
Если нам не помогут, то мы тоже никого не пощадим.
Re[2]: Optional Value. Уменьшение количества null reference-
Здравствуйте, IT, Вы писали:
IT>Это случайно не Null Object Pattern называется?
Скорее нет, чем да. Если пользоваться описаниями ссылка1, ссылка2, то Null Object Pattern предлагает делать кастомный интерфейс и кастомную реализацию Null Object-а для каждого случая. A OptionalValue один для всех .
Наиболее близкую ссылку я уже привел в первом посте Option type. Оттуда можно перейти, например, к реализации в Scala.
Здравствуйте, Alexander Polyakov, Вы писали:
IT>>Это случайно не Null Object Pattern называется? AP>Скорее нет, чем да. Если пользоваться описаниями ссылка1, ссылка2, то Null Object Pattern предлагает делать кастомный интерфейс и кастомную реализацию Null Object-а для каждого случая. A OptionalValue один для всех .
Это всё элементарно решается с помощью дженериков.
AP>Наиболее близкую ссылку я уже привел в первом посте Option type. Оттуда можно перейти, например, к реализации в Scala.
Или в Немерле. Но без ПМ этим пользоваться не очень удобно.
Если нам не помогут, то мы тоже никого не пощадим.
Re: Optional Value. Уменьшение количества null reference-ов.
Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать.
Вот мой вариант, завалявшихся со стародавних времен:
public abstract class Option<T>
{
class Just:Option<T>
{
T value;
public Just(T value)
{
this.value = value;
}
public override bool HasValue
{
get { return true; }
}
public override T Value
{
get { return this.value; }
}
}
class NoneClass:Option<T>
{
public override bool HasValue
{
get { return false; }
}
public override T Value
{
get { throw new InvalidOperationException("Value is empty"); }
}
}
public abstract T Value { get; }
public abstract bool HasValue { get; }
private Option()
{
}
public static readonly Option<T> None = new NoneClass();
public static Option<T> Create(T value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
return new Just(value);
}
public static implicit operator Option<T>(T value)
{
if (value != null)
{
return Create(value);
}
else
{
return None;
}
}
public static explicit operator T(Option<T> option)
{
return option.Value;
}
}
public static class Option
{
public static Option<T> None<T>()
{
return Option<T>.None;
}
public static Option<T> ToOption<T>(this T value)
{
return value;
}
public static Option<V> SelectMany<T,V>(this Option<T> value, Func<T, Option<V>> selector)
{
return value.HasValue ? selector(value.Value) : None<V>();
}
public static Option<V> SelectMany<T,K,V>(this Option<T> value, Func<T, Option<K>> selector, Func<T,K,V> resultSelector)
{
return value.SelectMany(left => selector(left).SelectMany(right => resultSelector(left, right).ToOption()));
}
public static Option<V> Select<T,V>(this Option<T> value, Func<T, V> selector)
{
return value.SelectMany(v => selector(v).ToOption());
}
public static Option<T> Where<T>(this Option<T> value, Func<T, bool> predicate)
{
return value.SelectMany(v => predicate(v) ? v.ToOption() : None<T>());
}
public static V Process<T,V>(this Option<T> value, Func<T, V> success, Func<V> fail)
{
return value.HasValue ? success(value.Value) : fail();
}
}
class Program
{
static void Main(string[] args)
{
var z1 = from c1 in 2.ToOption()
from c2 in 3.ToOption()
select c1 + c2;
Console.WriteLine(z1.HasValue);
Console.WriteLine(z1.Value);
var z2 = from c1 in 2.ToOption()
from c2 in 3.ToOption()
where c2 > 3
select c1 + c2;
Console.WriteLine(z2.HasValue);
}
}
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, Alexander Polyakov, Вы писали:
IT>Или в Немерле. Но без ПМ этим пользоваться не очень удобно.
Приведенное решение хорошо как раз тем, что использовать его можно без ПМ. Именно за без ПМ я и поставил оценку.
Кстати, проще было бы реализовать его именно через ПМ (то есть через тест типа)
Здравствуйте, IT, Вы писали:
IT>>>Это случайно не Null Object Pattern называется? AP>>Скорее нет, чем да. Если пользоваться описаниями ссылка1, ссылка2, то Null Object Pattern предлагает делать кастомный интерфейс и кастомную реализацию Null Object-а для каждого случая. A OptionalValue один для всех . IT>Это всё элементарно решается с помощью дженериков.
В описании паттерна четко фигурирует кастомный интерфейс (или абстрактный класс) с кастомным набором методов.
A Linked list is either a head element and a tail which is a list or empty (i.e. Null). Thus is makes sense to model an abstract linked list with a class List which has two methods getTail and accept as per the Visitor pattern [GHJV95, page 331]. http://www.cs.oberlin.edu/~jwalker/nullObjPattern/
Каким боком ты сюда дженерики вставишь? Уберешь этот кастомный интерфейс? Тогда это будет совсем не тот паттерн.
Такое ощущение, что ты ориентируешься только на слова в названии паттерна, попробуй почитать описание паттерна.
IT>Это всё элементарно решается с помощью дженериков.
Еще бы неплохо type inference более менее продвинутый иметь. Попробуй реализуй на Java-е.
IT>Но без ПМ этим пользоваться не очень удобно.
Пример кода с использование ПМ можно?
Re[5]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Qbit86, Вы писали:
Q>В C# для этих целей использую Option из Elevate Нет методов Process, нет перегруженных методов ProcessValue. А это ценно.
Нет ковариантности generic параметра. Поэтому нельзя пользоваться полиморфизмом по generic параметру, что очень печально.
Метод Select по правилам должен называться SelectMany.
Нет методов SelectMany и Select для поддержки query comprehension syntax.
Метод Some должен быть extension методом.
Используйте OptionalValue из Property Expression. Там это даже раньше появилось. По результатам обсуждения на форумах смерджу последнюю версию в Trunk, и выпущу новый релиз.
Здравствуйте, gandjustas, Вы писали:
G>Как-то слишком многословно
Где ты увидел многословность? Объем совпадает с твоим, просто у тебя отсутствуют некоторые полезные методы.
G>и к тому же не компилится, не хватает ToFunc.
Это мелочи, к тому же там была ссылка на сорци полного солюшена. Там все просто. Вот без ToFunc:
public static void Process<TValue>(
this IOptionalValue<TValue> optionalValue,
Action<TValue> existAction,
Action notExistAction)
{
optionalValue.Process(
value =>
{
existAction(value);
return new {};
},
() =>
{
notExistAction();
return new {};
});
}
G>Вот мой вариант, завалявшихся со стародавних времен: G>
G>public abstract class Option<T>
Главный недостаток твоего варианта -- нет ковариантности generic параметра. Поэтому нельзя пользоваться полиморфизмом по generic параметру, что очень печально.
G>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать.
Это замечание незначительно само по себе, а с учетом отсутствия ковариантности generic параметра в альтернативном (твоем) варианте значимость этого замечания пропадает вовсе.
Re[3]: Optional Value. Уменьшение количества null reference-
S>Да, мне это ближе!
Как я уже писал в первом посте. Метод Process и методы GetValue/HasValue выражаются друг через друга в обе стороны, ситуация симметричная. Да, можно ввести в интерфейс IOptionalValue свойства Value и HasValue, а метод Process наоборот перенести в extension методы (в моем текущем проекте именно так). Мои аргументы в пользу варианта из первого поста: Не хочется иметь в базовом интерфейсе свойство, кидающее исключение.
В случае если не срабатывает type inference, то для extension метода Process придется явно прописывать значения обоих generic параметров. А если Process является методом интерфейса, то прописывать придется значение только одного generic параметра.
Вы считаете эти аргументы незначительными?
По производительности вариант со свойствами Value/HasValue, наверное, лучше.
Re: Optional Value. Уменьшение количества null reference-ов.
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Хочется иметь такую технику кодирования, чтобы Extract Method не переводил ошибки компиляции в ошибки run time-а.
Правильное решение этой проблемы — использование контрактов и статической верификации. Если бы оно ешё работало...
AP> оба варианта ведут себя одинаково -- если код компилируется, то он работает.
Да. Но, вместо того, чтобы решать проблему в её источнике — методе, вы передаёте ответственность по соблюдению контракта всему остальному коду. NullReferenceException хотя бы гарантировал, что при ошибке в вашем коде программа упадёт. OptionalValue маскирует исходную проблему и источник её возникновения: "ой, у нас тут значения нет — фиг с ним, подсунем что-нить"
Re[4]: Optional Value. Уменьшение количества null reference-
S>>Да, мне это ближе!
Ближе собственно тем, что при работе с АТД используется один неполиморфный метод.
AP>Как я уже писал в первом посте. Метод Process и методы GetValue/HasValue выражаются друг через друга в обе стороны, ситуация симметричная. Да, можно ввести в интерфейс IOptionalValue свойства Value и HasValue, а метод Process наоборот перенести в extension методы (в моем текущем проекте именно так). AP>Мои аргументы в пользу варианта из первого поста: AP> AP>Не хочется иметь в базовом интерфейсе свойство, кидающее исключение. AP>В случае если не срабатывает type inference, то для extension метода Process придется явно прописывать значения обоих generic параметров. А если Process является методом интерфейса, то прописывать придется значение только одного generic параметра. AP>
1. Не нужны эти свойства, если пойти через тест типа аки в ПМ (здесь
2. Можно пример?
AP>Вы считаете эти аргументы незначительными?
нет.
AP>По производительности вариант со свойствами Value/HasValue, наверное, лучше.
вряд ли намного лучше. Копейки тут выжимать нет смысла, т.к. вся эта кухня куда дороже (по производительности) чем проверка на null.
З.Ы. В некоторых случаях может оказаться удобнее OptionalValue, построенный не на АТД, а на кортеже флага и значения. Такая штука шикарно передается в качестве параметров по умолчанию. Описано у desco.
Re[3]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>Как-то слишком многословно AP>Где ты увидел многословность? Объем совпадает с твоим, просто у тебя отсутствуют некоторые полезные методы.
Твой код в полтора раза больше.
Какие например?
У меня еще есть Where комбинатор.
G>>Вот мой вариант, завалявшихся со стародавних времен: G>>
G>>public abstract class Option<T>
AP>Главный недостаток твоего варианта -- нет ковариантности generic параметра. Поэтому нельзя пользоваться полиморфизмом по generic параметру, что очень печально.
Приведи пример где ковариантность необходима.
G>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>Это замечание незначительно само по себе,
Да ну? Сломать контракт это фигня?
AP>а с учетом отсутствия ковариантности generic параметра в альтернативном (твоем) варианте значимость этого замечания пропадает вовсе.
Приведи пример где ковариантность необходима.
Re[2]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Alexander Polyakov, Вы писали:
AP>>Хочется иметь такую технику кодирования, чтобы Extract Method не переводил ошибки компиляции в ошибки run time-а. S>Правильное решение этой проблемы — использование контрактов и статической верификации. Если бы оно ешё работало...
AP>> оба варианта ведут себя одинаково -- если код компилируется, то он работает. S>Да. Но, вместо того, чтобы решать проблему в её источнике — методе, вы передаёте ответственность по соблюдению контракта всему остальному коду. NullReferenceException хотя бы гарантировал, что при ошибке в вашем коде программа упадёт. OptionalValue маскирует исходную проблему и источник её возникновения: "ой, у нас тут значения нет — фиг с ним, подсунем что-нить"
Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает.
Re[3]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает.
Не спорю. Только топикстартер её использует для других целей:
Хочется иметь такую технику кодирования, чтобы Extract Method не переводил ошибки компиляции в ошибки run time-а.
Re: Optional Value. Уменьшение количества null reference-ов.
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Отсюда вывод: не использовать null в качестве возвращаемого значения! То есть набирать на клавиатуре null только: AP>Но наша цель более скромная – уменьшить количество null-ов. Кстати, по пунктам a и b еще можно кое-что отвоевать.
Не очень понятен смысл неиспользования null-ов. Проблема, я так понимаю, в том, что NRE упадёт слишком поздно?
AP>Как будет выглядеть приведенный выше пример в случае использования OptionalValue? AP>Делаем замену вызова конструктора "new SomeClass1()" на Nothing. Добиваемся, чтобы код компилировался, в итоге получаем первый вариант: AP>
AP>string someMethodResult = OptionalValue.Nothing<SomeClass1>().Process(
AP> value => value.SomeMethod1(),
AP> () => "[Экземпляр класса SomeClass1 не существует]");
AP>
второй вариант: AP>
AP>string someMethodResult = ExtractedMethod1().Process(
AP> value => value.SomeMethod1(),
AP> () => "[Экземпляр класса SomeClass1 не существует]");
AP>IOptionalValue<SomeClass1> ExtractedMethod1()
AP>{
AP> return OptionalValue.Nothing<SomeClass1>();
AP>}
AP>Таким образом, оба варианта ведут себя одинаково -- если код компилируется, то он работает.
Не очень понял, что будет происходить при возврате null из SomeMethod1(). Будет выброшен NRE? Или в консоль уедет "[Экземпляр класса SomeClass1 не существует]"?
AP>
The Maybe Monad
Да, OptionalValue является Maybe монадой. Но использование двух перегруженных методов ProcessValue часто оказывается удобнее использования разноименных монадных методов SelectMany и Select.
AP>Общественность уже понимает необходимость разделения nullable типов и не nullable типов. Но пока в майнстримовых языка/платформах это не реализовано. AP>
AP>A more elegant solution that will never come true is to apply value type syntax for reference types: all references are implicitly not nulls for the compiler, but a question mark after a type (ie: «string?» or «Customer?») allows you to set null to the variable.
AP>http://codevanced.net/post/One-Annotations-Way-Resharper.aspx
AP>
AP>1.0 Non-Null Types Many errors in modern programs manifest themselves as null-dereference errors, suggesting the importance of a programming language providing the ability to discriminate between expressions that may evaluate to null and those that are sure not to (for some experimental evidence, see [24, 22]). In fact, we would like to eradicate all null dereference errors.
AP>http://stackoverflow.com/questions/1943465/avoiding-null-reference-exceptions
AP>В Википеии это описано под термином Option type.
AP>
Source code of OptionalValue
Методы GetValue/HasValue можно поменять местами с методом интерфеса IOptionalValue.Process, т.е. GetValue/HasValue будут в интерфейсе, а Process будет extension методом, который будет выражаться через GetValue/HasValue. В этом случае GetValue можно сделать свойством Value. Я этого не делаю, вот по какой причине. Не хочется иметь в базовом интерфейсе свойство, кидающее исключение. Метод GetValue желательно дергать как можно реже.
Не вижу ничего плохого в выбросе исключения. Вопрос только в том, когда именно исключение кидать:
1. При компиляции, при попытке засунуть null в non-nullable объект => вроде бы невозможно на текущем уровне развития компилятора
2. При исполнении, при попытке прочитать null в non-nullable объекта => то же самое, что сейчас делает среда
3. При исполнении, при попытке засунуть null в non-nullable объект => вот это было бы полезно, но в ваших примерах я этого не вижу.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Alexander Polyakov, Вы писали:
AP>>Отсюда вывод: не использовать null в качестве возвращаемого значения! То есть набирать на клавиатуре null только: AP>>Но наша цель более скромная – уменьшить количество null-ов. Кстати, по пунктам a и b еще можно кое-что отвоевать. S>Не очень понятен смысл неиспользования null-ов. Проблема, я так понимаю, в том, что NRE упадёт слишком поздно?
Проблема в том что NRE вообще упадет.
Рассмотрим код:
var x = Method1().Method2().Method3().Method4();
Если везде возвращаются ref-типы, то каждый из методов может вернуть null.
Можно использовать контракты чтобы доказать что null не вернется.
Но иногда все таки методы возвращают null и это является нормальным поведением, а нас во всей операции интересует только конечный результат, тогда хорошо бы иметь способ описать частичные вычисления (которые могут не вернуть результата). В других языках есть конструкции типа .?, которые возвращают null если выражение слева null, но далеко не всегда есть возможность возвращать null, например если результат — value-type.
Вот и реализуют абстракции типа Option, которые позволяют избежать использования null и водопроводного кода типа:
var x1 = Method1();
if(x1 == null) return null;
var x2 = x1.Method2();
if(x2 == null) return null;
var x3 = x2.Method3();
if(x3 == null) return null;
return x3.Method4();
Но у обоих реализаций, представленных здесь, есть недостаток (Elevate им тоже обладает). Вполне можно написать так:
Здравствуйте, Qbit86, Вы писали:
AP>>Метод Select по правилам должен называться SelectMany. Q>По некоторым другим правилам должен называться и вовсе Bind, евпочя
Конечно это мелочи, но все же сделаю замечание. Мы в рамках C#-а. А здесь правила именования уже выбрали до нас. Монадический метод Bind назвали SelectMany. В частности, на второй перегруженный метод SelectMany завязан query comprehension syntax. Первый SelectMany в query comprehension syntax не участвует, но заменять пару перегруженных методов парой разноименных не очень удобно.
Re[5]: Optional Value. Уменьшение количества null reference-
Здравствуйте, samius, Вы писали:
S>Ближе собственно тем, что при работе с АТД используется один неполиморфный метод.
Метод с условным оператором внутри заметно лучше полиморфного метода?
S>1. Не нужны эти свойства, если пойти через тест типа аки в ПМ (здесь
).
Да, тест типа выглядит симпатичнее свойства HasValue (по крайней мере, на первый взгляд). Но, к сожалению, в C# это пока недоступно.
AP>>Мои аргументы в пользу варианта из первого поста: AP>> AP>>... AP>>В случае если не срабатывает type inference, то для extension метода Process придется явно прописывать значения обоих generic параметров. А если Process является методом интерфейса, то прописывать придется значение только одного generic параметра. AP>>S>2. Можно пример?
var result = optionalValue.Process<IA>(value => new B(), () => new C()); //если метод интерфейсаvar result = optionalValue.Process<SomeClass, IA>(value => new B(), () => new C()); //если extension методinterface IA {}
class B: IA { }
class C: IA { }
Кстати, 3-ий аргумент. Реализации свойств Value и HasValue в обязательном порядке должны быть согласованы: если HasValue возвращает true, то Value не должно кидать исключение. Для демонстрации этой проблемы приведу пример. Отмечу, что пример искусственный, эта же задача решается с помощью двух существующих реализаций IOptionalValue. Но все же. Никто не мешает добавить свою имплементацию интерфейса IOptionalValue, которая будет лезть на web service и брать оттуда значение. Если у интерфейса IOptionalValue всего один метод Process, то все прямолинейно и просто:
А попробуйте написать реализацию интерфейса с двумя методами :
public interface IOptionalValue<TValue>
{
TValue Value { get; }
bool HasValue { get; }
}
S>З.Ы. В некоторых случаях может оказаться удобнее OptionalValue, построенный не на АТД, а на кортеже флага и значения. Такая штука шикарно передается в качестве параметров по умолчанию. Описано у desco.
Спасибо, почитаю.
Re[6]: Optional Value. Уменьшение количества null reference-
AP>Кстати, 3-ий аргумент. Реализации свойств Value и HasValue в обязательном порядке должны быть согласованы: если HasValue возвращает true, то Value не должно кидать исключение. Для демонстрации этой проблемы приведу пример. Отмечу, что пример искусственный, эта же задача решается с помощью двух существующих реализаций IOptionalValue. Но все же. Никто не мешает добавить свою имплементацию интерфейса IOptionalValue, которая будет лезть на web service и брать оттуда значение. Если у интерфейса IOptionalValue всего один метод Process, то все прямолинейно и просто: AP>
А как будет выглядеть композиция таких методов?
Например надо получить от двух сервисов данные, как-то обработать их и отправить третьему.
AP>А попробуйте написать реализацию интерфейса с двумя методами :
А в чем сложность?
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
S>>Ближе собственно тем, что при работе с АТД используется один неполиморфный метод. AP>Метод с условным оператором внутри заметно лучше полиморфного метода?
Да, т.к. расширять иерархию нет надобности.
S>>1. Не нужны эти свойства, если пойти через тест типа аки в ПМ (здесь
). AP>Да, тест типа выглядит симпатичнее свойства HasValue (по крайней мере, на первый взгляд). Но, к сожалению, в C# это пока недоступно.
Разве оператор is пока недоступен?
S>>2. Можно пример? AP>
AP>var result = optionalValue.Process<IA>(value => new B(), () => new C()); //если метод интерфейса
AP>var result = optionalValue.Process<SomeClass, IA>(value => new B(), () => new C()); //если extension метод
AP>interface IA {}
AP>class B: IA { }
AP>class C: IA { }
AP>
решается через Process(value => (IA) new B(), () => (IA) new C());
AP>Кстати, 3-ий аргумент. Реализации свойств Value и HasValue в обязательном порядке должны быть согласованы: если HasValue возвращает true, то Value не должно кидать исключение. Для демонстрации этой проблемы приведу пример.
Я как раз и не настаиваю на наличии Value и HasValue.
AP>Отмечу, что пример искусственный, эта же задача решается с помощью двух существующих реализаций IOptionalValue. Но все же. Никто не мешает добавить свою имплементацию интерфейса IOptionalValue, которая будет лезть на web service и брать оттуда значение. Если у интерфейса IOptionalValue всего один метод Process, то все прямолинейно и просто:
AP>А попробуйте написать реализацию интерфейса с двумя методами :
Здесь я как раз предпочитаю чистый АТД, в том виде, в котором его например моделирует F#. Лишние реализации исключены.
Re[2]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinix, Вы писали:
AP>>Хочется иметь такую технику кодирования, чтобы Extract Method не переводил ошибки компиляции в ошибки run time-а. S>Правильное решение этой проблемы — использование контрактов и статической верификации. Если бы оно ешё работало...
Называть неработающее решение правильным как-то странно .
S>... использование контрактов и статической верификации. ...
Ага, можно использовать, а можно не использовать. То есть это является дополнением. И следовательно, это менее практично. С OptionValue ситуация другая, оно предлагает замену null-ам, а не дополнение. Почувствуйте разницу .
S>Да. Но, вместо того, чтобы решать проблему в её источнике — методе ...
Источник проблемы всегда в методе? Странное утверждение. Из него следует, что optional логика имеет право имплементироваться только внутри одного метода. Это бред.
AP>> оба варианта ведут себя одинаково -- если код компилируется, то он работает. S>Да. Но, вместо того, чтобы решать проблему в её источнике — методе, вы передаёте ответственность по соблюдению контракта всему остальному коду. NullReferenceException хотя бы гарантировал, что при ошибке в вашем коде программа упадёт. OptionalValue маскирует исходную проблему и источник её возникновения: "ой, у нас тут значения нет — фиг с ним, подсунем что-нить"
Странная у тебя логика, указания статического верификатора контрактов ты уважаешь, а на сообщения старого доброго компилятора реагируешь как “фиг с ним, подсунем что-нить”.
Re[3]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Скорее нет, чем да. Если пользоваться описаниями ссылка1, ссылка2, то Null Object Pattern предлагает делать кастомный интерфейс и кастомную реализацию Null Object-а для каждого случая. A OptionalValue один для всех .
Здравствуйте, gandjustas, Вы писали:
G>Приведи пример где ковариантность необходима. G>... G>Приведи пример где ковариантность необходима.
Ты вообще программируешь? Очень странно слышать такой вопрос от практикующего программиста.
Возьми любую задачу, где есть полиморфизм, например, пусть имеются типы TBase, TSubtype1 и TSubtype2. Добавь в эту задачу optional логику. Переменные исходных типов заменятся на IOptionalValue<TBase>, IOptionalValue<TSubtype1> и IOptionalValue<TSubtype2>. Если нет ковариантности, то метод с параметром IOptionalValue<TBase> не сможет принять объект типа IOptionalValue<TSubtype1>.
Re[5]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>Приведи пример где ковариантность необходима. G>>... G>>Приведи пример где ковариантность необходима. AP>Ты вообще программируешь? Очень странно слышать такой вопрос от практикующего программиста.
Вообще да.
AP>Возьми любую задачу, где есть полиморфизм, например, пусть имеются типы TBase, TSubtype1 и TSubtype2. Добавь в эту задачу optional логику. Переменные исходных типов заменятся на IOptionalValue<TBase>, IOptionalValue<TSubtype1> и IOptionalValue<TSubtype2>. Если нет ковариантности, то метод с параметром IOptionalValue<TBase> не сможет принять объект типа IOptionalValue<TSubtype1>.
Вот меня и интересует конкретный практический пример где такое нужно, а то в моей практике не встречалось.
Re[6]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
AP>>Возьми любую задачу, где есть полиморфизм, например, пусть имеются типы TBase, TSubtype1 и TSubtype2. Добавь в эту задачу optional логику. Переменные исходных типов заменятся на IOptionalValue<TBase>, IOptionalValue<TSubtype1> и IOptionalValue<TSubtype2>. Если нет ковариантности, то метод с параметром IOptionalValue<TBase> не сможет принять объект типа IOptionalValue<TSubtype1>. G>Вот меня и интересует конкретный практический пример где такое нужно, а то в моей практике не встречалось.
В моей встречались. Сейчас мне влом поднимать контекст конкретных задач, и вспоминать детали.
Re[7]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
AP>>>Возьми любую задачу, где есть полиморфизм, например, пусть имеются типы TBase, TSubtype1 и TSubtype2. Добавь в эту задачу optional логику. Переменные исходных типов заменятся на IOptionalValue<TBase>, IOptionalValue<TSubtype1> и IOptionalValue<TSubtype2>. Если нет ковариантности, то метод с параметром IOptionalValue<TBase> не сможет принять объект типа IOptionalValue<TSubtype1>. G>>Вот меня и интересует конкретный практический пример где такое нужно, а то в моей практике не встречалось. AP>В моей встречались. Сейчас мне влом поднимать контекст конкретных задач, и вспоминать детали.
То есть не так часто встречались чтобы это было значительным преимуществом для Option.
Re[7]: Optional Value. Уменьшение количества null reference-
Здравствуйте, samius, Вы писали:
S>>>Ближе собственно тем, что при работе с АТД используется один неполиморфный метод. AP>>Метод с условным оператором внутри заметно лучше полиморфного метода? S>Да, т.к. расширять иерархию нет надобности.
Не вижу как этот аргумент позволяет выделить “лучшего” в исходном утверждении. Оно показывает лишь то, что условный оператор может оказаться не хуже.
S>>>1. Не нужны эти свойства, если пойти через тест типа аки в ПМ (здесь
). AP>>Да, тест типа выглядит симпатичнее свойства HasValue (по крайней мере, на первый взгляд). Но, к сожалению, в C# это пока недоступно. S>Разве оператор is пока недоступен?
Если это обычный C#-вский оператор “is”, то твоя идея сводится к реализации метода HasValue(). У тебя не будет HasValue в базовом интерфейсе, а будет extention метод HasValue(). Опять таки, не вижу существенной разницы между полиморфным свойством и extention методом. А поскольку из-за желания ковариантности мы не может запретить создание других реализаций, то завязка на типы классов не очень хорошая идея.
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
AP>>>>Возьми любую задачу, где есть полиморфизм, например, пусть имеются типы TBase, TSubtype1 и TSubtype2. Добавь в эту задачу optional логику. Переменные исходных типов заменятся на IOptionalValue<TBase>, IOptionalValue<TSubtype1> и IOptionalValue<TSubtype2>. Если нет ковариантности, то метод с параметром IOptionalValue<TBase> не сможет принять объект типа IOptionalValue<TSubtype1>. G>>>Вот меня и интересует конкретный практический пример где такое нужно, а то в моей практике не встречалось. AP>>В моей встречались. Сейчас мне влом поднимать контекст конкретных задач, и вспоминать детали. G>То есть не так часто встречались чтобы это было значительным преимуществом для Option.
Вывод не верный. Экзамен по элементарной логике не сдан, приходите в следующий раз .
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
S>>>>Ближе собственно тем, что при работе с АТД используется один неполиморфный метод. AP>>>Метод с условным оператором внутри заметно лучше полиморфного метода? S>>Да, т.к. расширять иерархию нет надобности. AP>Не вижу как этот аргумент позволяет выделить “лучшего” в исходном утверждении. Оно показывает лишь то, что условный оператор может оказаться не хуже.
на мой вкус — лучше в конкретном случае. Навязывать и убеждать не собираюсь.
AP>>>Да, тест типа выглядит симпатичнее свойства HasValue (по крайней мере, на первый взгляд). Но, к сожалению, в C# это пока недоступно. S>>Разве оператор is пока недоступен? AP>Если это обычный C#-вский оператор “is”, то твоя идея сводится к реализации метода HasValue().
Сводится. Только зачем ее сводить?
AP>У тебя не будет HasValue в базовом интерфейсе, а будет extention метод HasValue().
Для чего он нужен?
AP>Опять таки, не вижу существенной разницы между полиморфным свойством и extention методом.
Полиморфное свойство не нужно.
AP>А поскольку из-за желания ковариантности мы не может запретить создание других реализаций, то завязка на типы классов не очень хорошая идея.
Другие реализации не нужны. Но запретить тебе их желать я не могу.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>>Это замечание незначительно само по себе, G>Да ну? Сломать контракт это фигня?
Какой контракт? Ты вообще о чем? Нет у меня никакого контракта. Ломать нечего!
G>>>Но я могу сколько угодно своих реализаций подсовывать.
Пожалуйста подсовывай, мой код будет корректно работать.
Re[9]: Optional Value. Уменьшение количества null reference-
Здравствуйте, samius, Вы писали:
AP>>А поскольку из-за желания ковариантности мы не может запретить создание других реализаций, то завязка на типы классов не очень хорошая идея. S>Другие реализации не нужны. Но запретить тебе их желать я не могу.
Мне они тоже не нужны. Мое желание -- иметь ковариантность.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Andrei N.Sobchuck, Вы писали:
AP>>Скорее нет, чем да. Если пользоваться описаниями ссылка1, ссылка2, то Null Object Pattern предлагает делать кастомный интерфейс и кастомную реализацию Null Object-а для каждого случая. A OptionalValue один для всех . ANS>Один или много объектов — это особенности реализации. См. Smalltalk, Objective-C.
А вот и нет.
Читаем статью по ссылке:
"[Одним из] недостатков является то, что паттерн 'Null Object' ... приводит к взрывному росту числа классов. Потому что необходимо создать свой 'пустой' класс для каждого абстрактного класса."
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>>>Это замечание незначительно само по себе, G>>Да ну? Сломать контракт это фигня? AP>Какой контракт? Ты вообще о чем? Нет у меня никакого контракта. Ломать нечего!
G>>>>Но я могу сколько угодно своих реализаций подсовывать. AP>Пожалуйста подсовывай, мой код будет корректно работать.
Твой — будет, а все вместе — нет.
Re[6]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>>>>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>>>>Это замечание незначительно само по себе, G>>>Да ну? Сломать контракт это фигня? AP>>Какой контракт? Ты вообще о чем? Нет у меня никакого контракта. Ломать нечего! G>
Что тебя так рассмешило?
G>... а все вместе — нет.
Код в студию.
Re[10]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
AP>>>А поскольку из-за желания ковариантности мы не может запретить создание других реализаций, то завязка на типы классов не очень хорошая идея. S>>Другие реализации не нужны. Но запретить тебе их желать я не могу. AP>Мне они тоже не нужны. Мое желание -- иметь ковариантность.
Ну ты же начал доказывать что ковариантность всем ой как нужна. А на деле не нужна.
Я собственно и до .NET4 не испытывал проблем из-за отсутствия ковариантности интерфейсов, где надо проделывал приведение типа ручками.
Для делегатов вариантность гораздо более существенна.
Re[11]: Optional Value. Уменьшение количества null reference
Здравствуйте, gandjustas, Вы писали:
G>А на деле не нужна.
Ковариантность нужна! Там где обычный полиморфизм + option логика = получаем необходимость ковариантности.
G>Я собственно и до .NET4 не испытывал проблем из-за отсутствия ковариантности интерфейсов, где надо проделывал приведение типа ручками.
Прописывать ковариантность ручками для option логики непозволительный синтаксический оверхед.
Re[10]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
AP>>>А поскольку из-за желания ковариантности мы не может запретить создание других реализаций, то завязка на типы классов не очень хорошая идея. S>>Другие реализации не нужны. Но запретить тебе их желать я не могу. AP>Мне они тоже не нужны. Мое желание -- иметь ковариантность.
Ковариантности не нужен полиморфный метод.
interface IOptionalValue<out T>
{
//TResult Process<TResult>(Func<T, TResult> f1, Func<TResult> f2);
}
class OptionalValue<T> : IOptionalValue<T>
{
private OptionalValue() {}
public sealed class NothingValue : OptionalValue<T> { }
public sealed class JustValue : OptionalValue<T>
{
public readonly T Value;
public JustValue(T value) { Value = value; }
}
}
Потому завязка на типы классов ничуть не хуже полиморфизма в аспекте ковариантности.
Re[12]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>А на деле не нужна. AP>Ковариантность нужна! Там где обычный полиморфизм + option логика = получаем необходимость ковариантности.
Удобна, но не необходима.
G>>Я собственно и до .NET4 не испытывал проблем из-за отсутствия ковариантности интерфейсов, где надо проделывал приведение типа ручками. AP>Прописывать ковариантность ручками для option логики непозволительный синтаксический оверхед.
Что же непозволительного в лишнем методе?
Re[13]: Optional Value. Уменьшение количества null reference
Здравствуйте, samius, Вы писали:
G>>>Я собственно и до .NET4 не испытывал проблем из-за отсутствия ковариантности интерфейсов, где надо проделывал приведение типа ручками. AP>>Прописывать ковариантность ручками для option логики непозволительный синтаксический оверхед. S>Что же непозволительного в лишнем методе?
Там, наверное, еще тип указывать надо, так? или я ошибаюсь? Желательно код увидеть.
Re[14]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
AP>>>Прописывать ковариантность ручками для option логики непозволительный синтаксический оверхед. S>>Что же непозволительного в лишнем методе? AP>Там, наверное, еще тип указывать надо, так? или я ошибаюсь? Желательно код увидеть.
С каких пор указание типа стало непозволительной роскошью для C#?
Re[11]: Optional Value. Уменьшение количества null reference
Здравствуйте, samius, Вы писали:
AP>>>>А поскольку из-за желания ковариантности мы не может запретить создание других реализаций, то завязка на типы классов не очень хорошая идея. S>>>Другие реализации не нужны. Но запретить тебе их желать я не могу. AP>>Мне они тоже не нужны. Мое желание -- иметь ковариантность. S>Ковариантности не нужен полиморфный метод. S>
S>interface IOptionalValue<out T>
S>{
S> //TResult Process<TResult>(Func<T, TResult> f1, Func<TResult> f2);
S>}
S>class OptionalValue<T> : IOptionalValue<T>
S>{
S> private OptionalValue() {}
S> public sealed class NothingValue : OptionalValue<T> { }
S> public sealed class JustValue : OptionalValue<T>
S> {
S> public readonly T Value;
S> public JustValue(T value) { Value = value; }
S> }
S>}
S>
S>Потому завязка на типы классов ничуть не хуже полиморфизма в аспекте ковариантности.
Ну в обсуждаемом вопросе все переплетается друг с другом. В таком варианте, да, ковариантность присутствует. Я думал, ты собираешься запрещать других наследников с помощью абстрактного класса вместо интерфейса. Если идем через интерфейс, то возможны другие наследники, а у тебя есть завязка в extension методах на конкретных наследников, что не хорошо.
Re[15]: Optional Value. Уменьшение количества null reference
Здравствуйте, samius, Вы писали:
AP>>>>Прописывать ковариантность ручками для option логики непозволительный синтаксический оверхед. S>>>Что же непозволительного в лишнем методе? AP>>Там, наверное, еще тип указывать надо, так? или я ошибаюсь? Желательно код увидеть. S>С каких пор указание типа стало непозволительной роскошью для C#?
Непозволительная роскошь в контексте реализации option логики. Если будет большой синтаксический оверхед будет возникать естественное желание побаловаться nuul-ами, а потом и не заметишь, как они разрастутся.
Re[12]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
S>>Потому завязка на типы классов ничуть не хуже полиморфизма в аспекте ковариантности. AP>Ну в обсуждаемом вопросе все переплетается друг с другом. В таком варианте, да, ковариантность присутствует. Я думал, ты собираешься запрещать других наследников с помощью абстрактного класса вместо интерфейса. Если идем через интерфейс, то возможны другие наследники, а у тебя есть завязка в extension методах на конкретных наследников, что не хорошо.
Да, не хорошо. Потому ковариантность в шею!
Re[16]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
AP>>>Там, наверное, еще тип указывать надо, так? или я ошибаюсь? Желательно код увидеть. S>>С каких пор указание типа стало непозволительной роскошью для C#? AP>Непозволительная роскошь в контексте реализации option логики. Если будет большой синтаксический оверхед будет возникать естественное желание побаловаться nuul-ами, а потом и не заметишь, как они разрастутся.
А я вообще эту кухню не воспринимаю серьезно в рамках C#-а. В F# создали довольно большую песочницу, где встретить null действительно сложно. Но как только выходишь за рамки этой песочницы и начинаешь взаимодействовать с FCL, null-ы все еще проблема. В C# вообще нет никакой песочницы, где бы не было null-ов.
Кроме этого, вряд ли в серьезном проекте, где разработчиков больше 3х, будет единодушие по поводу искоренения null-ов. Такое не исключено, но я не рассчитываю попасть в такой проект.
Re[17]: Optional Value. Уменьшение количества null reference
Здравствуйте, samius, Вы писали:
S>Кроме этого, вряд ли в серьезном проекте, где разработчиков больше 3х, будет единодушие по поводу искоренения null-ов. Такое не исключено, но я не рассчитываю попасть в такой проект.
Вопрос надо формулировать не как искоренение налов, а вот так. Каким образом реализовывать optional бизнес логику?
Re[7]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>>>>>Это замечание незначительно само по себе, G>>>>Да ну? Сломать контракт это фигня? AP>>>Какой контракт? Ты вообще о чем? Нет у меня никакого контракта. Ломать нечего! G>> AP>Что тебя так рассмешило?
То что у тебя нет контракта.
G>>... а все вместе — нет. AP>Код в студию.
Держи
class Ololo<T>: IOptionalValue<T>
{
public TResult Process<TResult>(Func<T, TResult> existFunc, Func<TResult> notExistFunc)
{
return default(TResult);
}
}
Re[12]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>А на деле не нужна. AP>Ковариантность нужна! Там где обычный полиморфизм + option логика = получаем необходимость ковариантности.
Бред же.
G>>Я собственно и до .NET4 не испытывал проблем из-за отсутствия ковариантности интерфейсов, где надо проделывал приведение типа ручками. AP>Прописывать ковариантность ручками для option логики непозволительный синтаксический оверхед.
Счегобы? Ты даже не смог пример привести где ковариантность была тебе необходима.
Re[16]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
AP>>>>>Прописывать ковариантность ручками для option логики непозволительный синтаксический оверхед. S>>>>Что же непозволительного в лишнем методе? AP>>>Там, наверное, еще тип указывать надо, так? или я ошибаюсь? Желательно код увидеть. S>>С каких пор указание типа стало непозволительной роскошью для C#? AP>Непозволительная роскошь в контексте реализации option логики. Если будет большой синтаксический оверхед будет возникать естественное желание побаловаться nuul-ами, а потом и не заметишь, как они разрастутся.
Да приведи уже пример.
Re[13]: Optional Value. Уменьшение количества null reference
Здравствуйте, gandjustas, Вы писали:
G>>>А на деле не нужна. AP>>Ковариантность нужна! Там где обычный полиморфизм + option логика = получаем необходимость ковариантности. G>Бред же.
В чем заключается бред, объяснить можешь?
G>>>Я собственно и до .NET4 не испытывал проблем из-за отсутствия ковариантности интерфейсов, где надо проделывал приведение типа ручками. AP>>Прописывать ковариантность ручками для option логики непозволительный синтаксический оверхед. G>Счегобы? Ты даже не смог пример привести где ковариантность была тебе необходима.
Не ври. Я не увидел зачем мне напрягаться. Пример потребует некоторых временных затрат. А ты опять не поймешь суть и прицепишься к несущественным моментам. Поэтому углубляться здесь на форуме в кастомные задачи я смысла не вижу. Если, действительно, есть желание, приходи к нам в офис, я тебе покажу код с моего экрана, а потом поговорим по коду.
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
S>>Кроме этого, вряд ли в серьезном проекте, где разработчиков больше 3х, будет единодушие по поводу искоренения null-ов. Такое не исключено, но я не рассчитываю попасть в такой проект. AP>Вопрос надо формулировать не как искоренение налов, а вот так. Каким образом реализовывать optional бизнес логику?
Так чтобы читать было удобно. Охота за налами не должна превращаться в самоцель. Осбенно в языке и фреймворке, заточенном на активное их использование.
Re[19]: Optional Value. Уменьшение количества null reference
Здравствуйте, samius, Вы писали:
S>>>Кроме этого, вряд ли в серьезном проекте, где разработчиков больше 3х, будет единодушие по поводу искоренения null-ов. Такое не исключено, но я не рассчитываю попасть в такой проект. AP>>Вопрос надо формулировать не как искоренение налов, а вот так. Каким образом реализовывать optional бизнес логику? S>Так чтобы читать было удобно. Охота за налами не должна превращаться в самоцель. Осбенно в языке и фреймворке, заточенном на активное их использование.
Читать код это самоцель? Я с кодом работаю, а это более широкое понятие.
Re[20]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
S>>Так чтобы читать было удобно. Охота за налами не должна превращаться в самоцель. Осбенно в языке и фреймворке, заточенном на активное их использование. AP>Читать код это самоцель? Я с кодом работаю, а это более широкое понятие.
Один?
Re[3]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>Проблема в том что NRE вообще упадет.
А! G>Рассмотрим код:
G>
G>var x = Method1().Method2().Method3().Method4();
G>
G>Если везде возвращаются ref-типы, то каждый из методов может вернуть null. G>Можно использовать контракты чтобы доказать что null не вернется.
Это совсем другая задача, чем та, которую ты обсуждаешь дальше. G>Но иногда все таки методы возвращают null и это является нормальным поведением, а нас во всей операции интересует только конечный результат, тогда хорошо бы иметь способ описать частичные вычисления (которые могут не вернуть результата). В других языках есть конструкции типа .?, которые возвращают null если выражение слева null, но далеко не всегда есть возможность возвращать null, например если результат — value-type.
G>Вот и реализуют абстракции типа Option, которые позволяют избежать использования null и водопроводного кода типа:
G>
Стесняюсь показаться ретроградом, но имхо этот "водопроводный" код менее многословен и более понятен, чем предложенная альтернатива. Можно показать мне, как классно будет записан вызов
var x = Method1().Method2().Method3().Method4();
так, чтобы в случае возврата null из любого из методов вместо NRE мы получили null в x?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, gandjustas, Вы писали:
G>>Вот и реализуют абстракции типа Option, которые позволяют избежать использования null и водопроводного кода типа:
G>>
S>Стесняюсь показаться ретроградом, но имхо этот "водопроводный" код менее многословен и более понятен, чем предложенная альтернатива. Можно показать мне, как классно будет записан вызов S>
S>var x = Method1().Method2().Method3().Method4();
S>
S>так, чтобы в случае возврата null из любого из методов вместо NRE мы получили null в x?
class Program
{
static void Main(string[] args)
{
TestV1();
TestV2();
}
static A Method1()
{
return null;
}
static IOptionalValue<A> TestV1()
{
return from x1 in Method1().ToOptionalValue()
from x2 in x1.Method2().ToOptionalValue()
from x3 in x2.Method3().ToOptionalValue()
select x3.Method4();
}
static IOptionalValue<A> TestV2()
{
return Method1().ToOptionalValue().SelectMany(x1 =>
x1.Method2().ToOptionalValue().SelectMany(x2 =>
x2.Method3().ToOptionalValue().SelectMany(x3 =>
x3.Method4().ToOptionalValue())));
}
}
class A {}
static class AExtensions
{
public static A Method2(this A a)
{
return a;
}
public static A Method3(this A a)
{
return a;
}
public static A Method4(this A a)
{
return a;
}
}
Я лишь показал. Не настаиваю на том что это понятнее.
Впрочем, я уверен, что Sinclair-то знает о чем речь!
Re[4]: Optional Value. Уменьшение количества null reference-
S>Стесняюсь показаться ретроградом, но имхо этот "водопроводный" код менее многословен и более понятен, чем предложенная альтернатива. Можно показать мне, как классно будет записан вызов S>
S>var x = Method1().Method2().Method3().Method4();
S>
S>так, чтобы в случае возврата null из любого из методов вместо NRE мы получили null в x?
Для честного сравнения надо сначала переписать "водопроводный" код "так, чтобы в случае возврата null из любого мы получили null в x".
Re[5]: Optional Value. Уменьшение количества null reference-
Все не так просто.
На самом деле твой код, как и мой в TestV1 не прекратит вычисления при получении null-а. В MethodX он не зайдет, но ProcessValue будет вызван столько раз, сколько написано (то же касается SelectMany из TestV1).
А TestV2 действительно закончит вычисления при получении null-а.
Re[6]: Optional Value. Уменьшение количества null reference-
Во-первых, я полагал, что все понимают, что при переходе на OptionalVallue null-ы надо заменять на Nothing.
S>Все не так просто. S>На самом деле твой код, как и мой в TestV1 не прекратит вычисления при получении null-а. В MethodX он не зайдет, но ProcessValue будет вызван столько раз, сколько написано (то же касается SelectMany из TestV1). S>А TestV2 действительно закончит вычисления при получении null-а.
А зачем считать количество заходов в метод?
S>... В MethodX он не зайдет...
И это главное .
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
AP>Во-первых, я полагал, что все понимают, что при переходе на OptionalVallue null-ы надо заменять на Nothing.
А для чего тебе тогда SelectMany?
S>>Все не так просто. S>>На самом деле твой код, как и мой в TestV1 не прекратит вычисления при получении null-а. В MethodX он не зайдет, но ProcessValue будет вызван столько раз, сколько написано (то же касается SelectMany из TestV1). S>>А TestV2 действительно закончит вычисления при получении null-а. AP>А зачем считать количество заходов в метод?
S>>... В MethodX он не зайдет... AP>И это главное .
Когда делали Query синтакс, тоже так посчитали. А по-моему это лажа, заходить в методы, которые не учавствуют в вычислениях.
Re[9]: Optional Value. Уменьшение количества null reference-
Здравствуйте, samius, Вы писали:
AP>>Во-первых, я полагал, что все понимают, что при переходе на OptionalVallue null-ы надо заменять на Nothing. S>А для чего тебе тогда SelectMany?
Второй из перегруженных методов SelectMany нужен для query comprehension syntax. А первый вводился уже в дополнение, для полной аналогии с LINQ. В принципе, его можно убрать. Спасибо за замечание.
При всем при этом разноименные методы SelectMany и Select часто менее удобны, чем одноименные методы с такими же сигнатурой и смыслом, поэтому есть два метода ProcessValue. Вариант без ProcessValue и переименование первого SelectMany в Select тоже рассматривался ... .
Re[10]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
AP>>>Во-первых, я полагал, что все понимают, что при переходе на OptionalVallue null-ы надо заменять на Nothing. S>>А для чего тебе тогда SelectMany? AP>Второй из перегруженных методов SelectMany нужен для query comprehension syntax. А первый вводился уже в дополнение, для полной аналогии с LINQ. В принципе, его можно убрать. Спасибо за замечание.
Странно, что тебе оказался не нужен класический монадный bind (>>=), а сгодился его странноватый гибрид с проекцией.
AP>При всем при этом разноименные методы SelectMany и Select часто менее удобны, чем одноименные методы с такими же сигнатурой и смыслом, поэтому есть два метода ProcessValue. Вариант без ProcessValue и переименование первого SelectMany в Select тоже рассматривался ... .
Т.е. фактически bind в map? Хотел всех запутать?
Re[11]: Optional Value. Уменьшение количества null reference
Здравствуйте, samius, Вы писали:
AP>>>>Во-первых, я полагал, что все понимают, что при переходе на OptionalVallue null-ы надо заменять на Nothing. S>>>А для чего тебе тогда SelectMany? AP>>Второй из перегруженных методов SelectMany нужен для query comprehension syntax. А первый вводился уже в дополнение, для полной аналогии с LINQ. В принципе, его можно убрать. Спасибо за замечание. S>Странно, что тебе оказался не нужен класический монадный bind (>>=), а сгодился его странноватый гибрид с проекцией.
Метод нужен, вопрос лишь в его имени и в перегрузке с другими.
AP>>При всем при этом разноименные методы SelectMany и Select часто менее удобны, чем одноименные методы с такими же сигнатурой и смыслом, поэтому есть два метода ProcessValue. Вариант без ProcessValue и переименование первого SelectMany в Select тоже рассматривался ... . S>Т.е. фактически bind в map? Хотел всех запутать?
Монады монадами, а c OptionalValue удобнее работать через одноименные методы. Из примера выше:
var x = Method1()
.ProcessValue(_ => _.Method2())
.ProcessValue(_ => _.Method3())
.ProcessValue(_ => _.Method4());
Здесь любой из методов MethodX может возвращать как T так и IOptionalValue<T> запись от этого не меняется. И это классно .
Re[12]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
S>>Странно, что тебе оказался не нужен класический монадный bind (>>=), а сгодился его странноватый гибрид с проекцией. AP>Метод нужен, вопрос лишь в его имени и в перегрузке с другими.
Я привык отождествлять деятельность метода с названием. Если я знаю что короткий SelectMany это bind, а Select — это map, то любые перемены будут мешать.
S>>Т.е. фактически bind в map? Хотел всех запутать? AP>Монады монадами, а c OptionalValue удобнее работать через одноименные методы. Из примера выше: AP>
Здесь любой из методов MethodX может возвращать как T так и IOptionalValue<T> запись от этого не меняется. И это классно .
Не вижу ничего классного. Перемешаны монадные bind-ы с функторами, визуально не отличить что где.
Но самое что интересное, для такой записи не нужны OptionalValue<T>.
static TResult ProcessValue<T, TResult>(this T value, Func<T, TResult> func)
where T : class
where TResult : class
{
return (value != null) ? func(value) : default(TResult);
}
Re[14]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>А на деле не нужна. AP>>>Ковариантность нужна! Там где обычный полиморфизм + option логика = получаем необходимость ковариантности. G>>Бред же. AP>В чем заключается бред, объяснить можешь?
В том что необходимости ковариантности нету. Вообще вариантность заменяется обычным приведением типа.
G>>>>Я собственно и до .NET4 не испытывал проблем из-за отсутствия ковариантности интерфейсов, где надо проделывал приведение типа ручками. AP>>>Прописывать ковариантность ручками для option логики непозволительный синтаксический оверхед. G>>Счегобы? Ты даже не смог пример привести где ковариантность была тебе необходима. AP>Не ври. Я не увидел зачем мне напрягаться. Пример потребует некоторых временных затрат. А ты опять не поймешь суть и прицепишься к несущественным моментам. Поэтому углубляться здесь на форуме в кастомные задачи я смысла не вижу. Если, действительно, есть желание, приходи к нам в офис, я тебе покажу код с моего экрана, а потом поговорим по коду.
Запости код сюда и поговорим здесь. А то пока только голословные утверждения о необходимости ковариантности.
Re[4]: Optional Value. Уменьшение количества null reference-
S>Стесняюсь показаться ретроградом, но имхо этот "водопроводный" код менее многословен и более понятен, чем предложенная альтернатива. Можно показать мне, как классно будет записан вызов S>
S>var x = Method1().Method2().Method3().Method4();
S>
S>так, чтобы в случае возврата null из любого из методов вместо NRE мы получили null в x?
var x = from x1 in Method1().ToOption()
from x2 in x1.Method2().ToOption()
from x3 in x2.Method3().ToOption()
select x3.Method4();
Естественно куча ифов, как выше — это самый простой случай частичных вычислений. Option<T> позволяет не только чуть более лаконично описывать это безобразие, но и декомпозировать его.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
S>Стесняюсь показаться ретроградом, но имхо этот "водопроводный" код менее многословен и более понятен, чем предложенная альтернатива.
Монада List (Linq 2 Objects) относится к циклам определенного вида, примерно как монада Maybe (Option) к ифам определенного вида. При грамотном использовании позволяет сделать код более наглядным и не прятать логику под тоннами управляющих конструкций.
Re[13]: Optional Value. Уменьшение количества null reference
Здравствуйте, samius, Вы писали:
S>Я привык отождествлять деятельность метода с названием.
Это хорошо.
S>Если я знаю что короткий SelectMany это bind, а Select — это map, то любые перемены будут мешать.
А тут как раз идет отождествление названия с названием.
S>Не вижу ничего классного. Перемешаны монадные bind-ы с функторами, визуально не отличить что где.
Попробуй оторваться на минутку от общих монад и подумать над частным вопросом опциональных значений.
S>Но самое что интересное, для такой записи не нужны OptionalValue<T>.
Ага, я это знаю . Только остается вопрос, когда такой записью пользоваться? Для всех переменных? Нет, спасибо, не буду.
OptionalValue как раз и служит для разделение опциональных и не опциональных переменных. Соответственно, для первых применяем такую запись, а для вторых обычную. А какой будет переменная T или IOptionalValue<T> определяет поставщик переменной. Если мы знаем, что поставщик соблюдает это правило, то для T можно не беспокоиться об NRE. Если поставщик не соблюдает это правило, то все как обычно, т.е. хреново: писать или не писать if, если писать, то, что внутри этого if-а делать и т.д. Глупость заключается в том, чтобы создавать эту хреновую ситуацию и в случае, если вы сами являетесь тем поставщиком.
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>>>>>>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>>>>>>Это замечание незначительно само по себе, G>>>>>Да ну? Сломать контракт это фигня? AP>>>>Какой контракт? Ты вообще о чем? Нет у меня никакого контракта. Ломать нечего! G>>> AP>>Что тебя так рассмешило? G>То что у тебя нет контракта.
G>>>... а все вместе — нет. AP>>Код в студию.
G>Держи
G>
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>>>>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>>>>>>>Это замечание незначительно само по себе, G>>>>>>Да ну? Сломать контракт это фигня? AP>>>>>Какой контракт? Ты вообще о чем? Нет у меня никакого контракта. Ломать нечего! G>>>> AP>>>Что тебя так рассмешило? G>>То что у тебя нет контракта.
G>>>>... а все вместе — нет. AP>>>Код в студию.
G>>Держи
G>>
AP>нету. Поэтому в этой ветке ты молча слил, я правильно понимаю?
Не веди себя как дите.
При такой реализации IOptionalValue метода HasValue вернет false, а GetValue не бросит исключение. Я еще не проверял как у тебя Linq в таком случае заработает.
Это и есть контракт, который у тебя не энфорсится никак.
Re[9]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали: AP>Для честного сравнения надо сначала переписать "водопроводный" код "так, чтобы в случае возврата null из любого мы получили null в x".
Ну давайте перепишем:
Type1 x = null;
var x1 = Method1();
if(x1 != null)
{
var x2 = x1.Method2();
if(x2 != null)
{
var x3 = x2.Method3();
if(x3 != null)
x = x3.Method4();
}
}
Это что-то принципиально поменяет?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
AP>>Для честного сравнения надо сначала переписать "водопроводный" код "так, чтобы в случае возврата null из любого мы получили null в x". S>Ну давайте перепишем: S>
S>Type1 x = null;
S>var x1 = Method1();
S>if(x1 != null)
S>{
S> var x2 = x1.Method2();
S> if(x2 != null)
S> {
S> var x3 = x2.Method3();
S> if(x3 != null)
S> x = x3.Method4();
S> }
S>}
S>
S>Это что-то принципиально поменяет?
Опа, вместо просто инициализации переменной получили изменяемое состояние. В исходном “водопроводном” варианте изменяемого состояния не было!
Просто инициализация выглядит так:
Type1 x;
var x1 = Method1();
if (x1 == null)
x = null;
else
{
var x2 = x1.Method2();
if (x2 == null)
x = null;
else
{
var x3 = x2.Method3();
if (x3 == null)
x = null;
else
x = x3.Method4();
}
}
Далее: Надо ли показывать к каким косякам может привести изменяемое состояние в данном случае?
В каком варианте будем подсчитывать многословность (количество слов)?
Вариант c OptionalValue:
var x = Method1()
.ProcessValue(_ => _.Method2())
.ProcessValue(_ => _.Method3())
.ProcessValue(_ => _.Method4());
При подсчете количества слов у меня получилось, что вариант c OptionalValue побеждает любой из трех вариантов с if-ами. Детали подсчета оформлю в виде текста и запощу, если это потребуется.
Re[2]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
S>Не очень понятен смысл неиспользования null-ов. Проблема, я так понимаю, в том, что NRE упадёт слишком поздно?
Смысл -- сделать безопасным базовый/основополагающий прием трансформации кода Extract Method. Т.е. избежать катастрофы при использовании Extract Method, которая описана в первом посте.
Re[2]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
S>Не очень понятен смысл неиспользования null-ов. Проблема, я так понимаю, в том, что NRE упадёт слишком поздно?
Вот здесь развернутый комментарий:
OptionalValue как раз и служит для разделение опциональных и не опциональных переменных. Соответственно, для первых применяем такую запись, а для вторых обычную. А какой будет переменная T или IOptionalValue<T> определяет поставщик переменной. Если мы знаем, что поставщик соблюдает это правило, то для T можно не беспокоиться об NRE. Если поставщик не соблюдает это правило, то все как обычно, т.е. хреново: писать или не писать if, если писать, то, что внутри этого if-а делать и т.д. Глупость заключается в том, чтобы создавать эту хреновую ситуацию и в случае, если вы сами являетесь тем поставщиком. http://rsdn.ru/forum/design/3954267.1.aspx
AP>>где, что не работает? G>При такой реализации IOptionalValue метода HasValue вернет false, а GetValue не бросит исключение.
Нет такого требования!
G>Это и есть контракт, который у тебя не энфорсится никак.
Нет там никакого "кролика"(контракта) . Контракт только в твоей голове. Освободи свое сознание от шаблонов, навязанных твоей реализацией.
Re[10]: Optional Value. Уменьшение количества null reference
, но не удосужился написать ответ. G>Молча слил?
В своем посте я сделал замечание, чтобы не делали то-то и то-то, поскольку пример искусственный. Ты в своем посте сделал ровно то, что было в замечании. Ставлю минус, когда собеседник не слышит меня, и я теряю интерес к продолжению разговора.
G>Молча слил?
Минус это не “молча”.
Re[11]: Optional Value. Уменьшение количества null reference
AP>>>где, что не работает? G>>При такой реализации IOptionalValue метода HasValue вернет false, а GetValue не бросит исключение. AP>Нет такого требования!
G>>Это и есть контракт, который у тебя не энфорсится никак. AP>Нет там никакого "кролика"(контракта) . Контракт только в твоей голове. Освободи свое сознание от шаблонов, навязанных твоей реализацией.
Любая реализация Option должна быть изоморфна любой другой. Иначе нарушаешь принцип наименьшего удивления.
Re[11]: Optional Value. Уменьшение количества null reference
, но не удосужился написать ответ. G>>Молча слил? AP>В своем посте я сделал замечание, чтобы не делали то-то и то-то, поскольку пример искусственный. Ты в своем посте сделал ровно то, что было в замечании. Ставлю минус, когда собеседник не слышит меня, и я теряю интерес к продолжению разговора.
А я не должен делать как ты говоришь, ты привел пример кода, я привел аналогичный пример со своей реализацией Option, ты ничего не сказал, только минус поставил. Кроме того на вопрос не ответил, а вопрос кстати очень важный.
ЗЫ. Ты вообще не воспринимаешь критику, сразу начинаешь съезжать и придумывать небылицы. Например: нету контракта, необходима ковариантность итп. Уже не первый раз так. Не можешь адекватно вести разговор — лучше не пиши сюда.
Re[3]: Optional Value. Уменьшение количества null reference-
S>>Не очень понятен смысл неиспользования null-ов. Проблема, я так понимаю, в том, что NRE упадёт слишком поздно? AP>Смысл -- сделать безопасным базовый/основополагающий прием трансформации кода Extract Method. Т.е. избежать катастрофы при использовании Extract Method, которая описана в первом посте.
Дело в том, что я не вижу никакой катастрофы.
Вот у нас был безопасный код — мы его отрефакторили. Я надеюсь, очевидно, что в исходном коде не было никаких null.Method2()? Значит, после рефакторинга код никак не поменяет свою работоспособность.
Вторая проблема: нигде в последующем обсуждении я не вижу примера того, как Extract Method станет более безопасным. Точнее, вообще нигде нет никаких Extract Method.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Скажи, а вот ты серьёзно считаешь, что вот эти [перловские] подчёркивания (да ещё в сочетании с "=>") читабельнее шарповых слов (а хотя бы и букв) в именах переменных?
Здравствуйте, akasoft, Вы писали:
A>Скажи, а вот ты серьёзно считаешь, что вот эти [перловские] подчёркивания (да ещё в сочетании с "=>") читабельнее шарповых слов (а хотя бы и букв) в именах переменных?
Они не перловские, они хаскельные и окамловские. Иногда их употребление вполне уместно.
Глаза у меня добрые, но рубашка — смирительная!
Re[12]: Optional Value. Уменьшение количества null reference
Здравствуйте, gandjustas, Вы писали:
G>Любая реализация Option должна быть изоморфна любой другой.
Хватит уже пытаться подсунуть требования, которых нет! И которые не нужны.
G>Любая реализация Option должна быть изоморфна любой другой. Иначе нарушаешь принцип наименьшего удивления.
Если я сделаю реализацию IComparer, который будет говорить что 3 больше 2. Отсортирую им массив. Как тут насчет принципа наименьшего удивления?
A>Скажи, а вот ты серьёзно считаешь, что вот эти [перловские] подчёркивания (да ещё в сочетании с "=>") читабельнее шарповых слов (а хотя бы и букв) в именах переменных?
Стоит решить одну/две задачи с помощью такой конструкции, сравнить ее с альтернативной реализацией, и претензии отпадут сами собой.
Здравствуйте, Qbit86, Вы писали:
Q>Здравствуйте, akasoft, Вы писали:
A>>Скажи, а вот ты серьёзно считаешь, что вот эти [перловские] подчёркивания (да ещё в сочетании с "=>") читабельнее шарповых слов (а хотя бы и букв) в именах переменных?
Q>Они не перловские, они хаскельные и окамловские. Иногда их употребление вполне уместно.
Разве что в ML языках подчеркивание применяется в ситуациях, когда значение не используется. Здесь же подчеркивание есть имя используемой переменной.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
S>Я надеюсь, очевидно, что в исходном коде не было никаких null.Method2()?
Да, не было.
S>Дело в том, что я не вижу никакой катастрофы. S>Вот у нас был безопасный код — мы его отрефакторили. Я надеюсь, очевидно, что в исходном коде не было никаких null.Method2()? Значит, после рефакторинга код никак не поменяет свою работоспособность.
Работоспособность не изменилась, да, но надежность/безопасность снизилась. Снижение надежности вот в каком смысле. Программист делает неправильные действия, а компилятор не сообщает ему об ошибке. В коде до рефакторинга мы делаем неправильное действие: заменяем вызов конструктора “new SomeClass1()” на “null” и компилятор говорит нам “вы что-то не то делаете”. После рефакторинга, если мы сделаем такое же неправильное действие, то получим NRE только в runtime-е.
S>Вторая проблема: нигде в последующем обсуждении я не вижу примера того, как Extract Method станет более безопасным. Точнее, вообще нигде нет никаких Extract Method.
Извиняюсь, но этот абзац я не понял. В каких обсуждениях, какой пример? Пример с Extract Method-ом уже был в первом посте в разделе “Катастрофа при Extract Method”.
S>Точнее, вообще нигде нет никаких Extract Method.
В реальности этап с Extract Method-ом часто не присутствует в явном виде. Программист не рефакторит, а сразу пишет метод (или это делает вообще другой человек). Но описанная проблема присутствует и здесь. Надежность такого кода ниже по сравнению с тем, который получается после Inline Method.
Пример из реального проекта, где нужна ковариантность OptionalValue:
private static IOptionalValue<IFollowingPublicationCalculator> GetFollowingPublicationCalculator(
string catalogNumber, string precededCatalogNumber, int releaseMark)
{
if (string.IsNullOrEmpty(precededCatalogNumber))
{
return FindPreviousPublicationIdBySelfNumber(catalogNumber, releaseMark)
.ProcessValue(value => new SelfNumberFollowingPublicationCalculator(value, catalogNumber));
}
else
{
return FindPreviousPublicationIdByOtherNumber(precededCatalogNumber)
.ProcessValue(value => new OtherNumberFollowingPublicationCalculator(value, precededCatalogNumber));
}
}
Так код будет выглядеть под C# 4.0. Причем сейчас этот код под C# 3.0, и я вырезал ручные операции с типами. Вариантов записи с ручными операциями над типами много, поэтому жду, какой вариант нравится вам. Мне все варианты не нравятся, хотя в них букв не много, и если будет достаточное обоснование, то можно смириться.
через абстрактный класс рассуждения про какой-то контракт это полная чушь, конечно. Но там есть другой приятный момент. Там есть implicit operator. Т.е. кое-где не будет требоваться вызов метода “.AsOptionalValue()”.
Вот думаю, что лучше ковариантность или implicit operator? Сделать и то и другое в текущей версии C#-а, к сожалению, нельзя.
Re[13]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>Любая реализация Option должна быть изоморфна любой другой. AP>Хватит уже пытаться подсунуть требования, которых нет! И которые не нужны.
Это ковариантность не нужна, ты до сих пор пример привести не смог даже.
А вот согласованность получения значение option и проверки наличия значения очень даже нужны. Просто потому что они в других библиотеках так сделаны.
G>>Любая реализация Option должна быть изоморфна любой другой. Иначе нарушаешь принцип наименьшего удивления. AP>Если я сделаю реализацию IComparer, который будет говорить что 3 больше 2. Отсортирую им массив. Как тут насчет принципа наименьшего удивления?
Не то сравниваешь. Тут вопрос согласованности, вот если ты сделаешь класс у которого не выполняется a.Equals(b) => a.GetHashCode() == b.GetHashCode(), то удивление будет ого-го, особенно при использовании в контейнерах.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
S> ... как Extract Method станет более безопасным. ...
Extract Method становится безопасным при использовании техники кодирования, описанной в разделе “Катастрофа при Extract Method”.
Re[5]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали: AP>Работоспособность не изменилась, да, но надежность/безопасность снизилась. Снижение надежности вот в каком смысле. Программист делает неправильные действия, а компилятор не сообщает ему об ошибке. В коде до рефакторинга мы делаем неправильное действие: заменяем вызов конструктора “new SomeClass1()” на “null” и компилятор говорит нам “вы что-то не то делаете”. После рефакторинга, если мы сделаем такое же неправильное действие, то получим NRE только в runtime-е.
Вы серъёзно? Лично мне описанный сценарий кажется слегка надуманным. Программист в здравом уме никогда даже не попробует заменить “new SomeClass1()” на “null”. Ни до рефакторинга, ни после.
Более реалистичным представляется замена new SomeClass1() на SomeClassFactory.Instance.GetInstance(). Но что-то мне подсказывает, что возврат null из SomeClassFactory не отловится ни компилятором, ни вашим OptionalValue.
AP>Извиняюсь, но этот абзац я не понял. В каких обсуждениях, какой пример? Пример с Extract Method-ом уже был в первом посте в разделе “Катастрофа при Extract Method”.
Нет примера того, как катастрофы Extract Method удаётся избежать при помощи OptionalValue. Может, я что-то пропустил?
Покажите мне код с экстрагированным методом, который упадёт при использовании OptionalValue, в отличие от кода без использования OptionalValue.
AP>В реальности этап с Extract Method-ом часто не присутствует в явном виде. Программист не рефакторит, а сразу пишет метод (или это делает вообще другой человек). Но описанная проблема присутствует и здесь. Надежность такого кода ниже по сравнению с тем, который получается после Inline Method.
Я, наверное, очень далёк уже от практики программирования. Я ни разу в жизни не наблюдал ошибки компилятора, о которой вы пишете. Как правило, мат ставится в два хода:
1. var x = null; // иногда — var x = GetSomeX(), который возвращает null
2. x.CallMethodRequiringNotNull(); // NRE
Против этого ваш OptionalValue ничего интересного не предлагает. Как, впрочем, и компилятор.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Optional Value. Уменьшение количества null reference
. Ковариантность нужна .
G>>>Любая реализация Option должна быть изоморфна любой другой. AP>>Хватит уже пытаться подсунуть требования, которых нет! И которые не нужны. G>... согласованность получения значение option и проверки наличия значения очень даже нужны. Просто потому что они в других библиотеках так сделаны.
Поведение моих реализаций согласовано с аналогичными реализациями в других библиотеках. Ты дописываешь свою реализацию, которую делаешь несогласованной с другими библиотеками. Почему претензии к результатам работы моего кода? Мой код делает ровно то, что заявлено, не больше, не меньше.
G>>>Любая реализация Option должна быть изоморфна любой другой. Иначе нарушаешь принцип наименьшего удивления. AP>>Если я сделаю реализацию IComparer, который будет говорить что 3 больше 2. Отсортирую им массив. Как тут насчет принципа наименьшего удивления? G>Не то сравниваешь. Тут вопрос согласованности, вот если ты сделаешь класс у которого не выполняется a.Equals(b) => a.GetHashCode() == b.GetHashCode(), то удивление будет ого-го, особенно при использовании в контейнерах.
Неплохая аналогия, да, тут надо делать согласованную реализацию двух методов. Аналогичные проблемы я отмечал для варианта, когда в интерфейсе IOptionalValue два свойства Value и HasValue. В моем коде у IOptionalValue метод один, поэтому согласовывать нечего.
Re[6]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
AP>>Работоспособность не изменилась, да, но надежность/безопасность снизилась. Снижение надежности вот в каком смысле. Программист делает неправильные действия, а компилятор не сообщает ему об ошибке. В коде до рефакторинга мы делаем неправильное действие: заменяем вызов конструктора “new SomeClass1()” на “null” и компилятор говорит нам “вы что-то не то делаете”. После рефакторинга, если мы сделаем такое же неправильное действие, то получим NRE только в runtime-е. S>Вы серъёзно? Лично мне описанный сценарий кажется слегка надуманным. Программист в здравом уме никогда даже не попробует заменить “new SomeClass1()” на “null”. Ни до рефакторинга, ни после. S>Более реалистичным представляется замена new SomeClass1() на SomeClassFactory.Instance.GetInstance(). Но что-то мне подсказывает, что возврат null из SomeClassFactory не отловится ни компилятором, ни вашим OptionalValue.
Ага, я уже догадался, что вы напишете такое. И с некоторым запозданием я добавил комментарий:
Extract Method становится безопасным при использовании техники кодирования, описанной в разделе “Катастрофа при Extract Method”. http://rsdn.ru/forum/design/3955011.1.aspx
Вы его заметили? Полное описание техники кодирования в первом посте. Если в вкратце, то это: не использование “return null(схематичное обозначение)” + OptionalValue.
S>Покажите мне код с экстрагированным методом, который упадёт при использовании OptionalValue, в отличие от кода без использования OptionalValue.
В абзаце выше уже написал, что OptionalValue в сочетании c не использованием “return null(схематичное обозначение)”.
AP>>Как правило, мат ставится в два хода: S>1. var x = null; // иногда — var x = GetSomeX(), который возвращает null S>2. x.CallMethodRequiringNotNull(); // NRE
Ага, именно это я и хотел показать Extract Method-ом, что проблема возникает как раз при разбиении задачи на два хода.
S>Против этого ваш OptionalValue ничего интересного не предлагает. Как, впрочем, и компилятор.
OptionalValue нацелен не напрямую на это. Его прямая цель -- реализация optional логики. Да, наверное, в заголовок лучше вынести последнее. Сейчас не самый удачный заголовок.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, IT, Вы писали:
IT>Но без ПМ этим пользоваться не очень удобно.
Всё же чем не удобно? Я почти не знаком с pattern-matching, но пока я вижу, что в частном случае опциональных значений совпадении один к одному с OptionalValue. Например:
Pattern-matching
match dict.TryGetValue "Brian" with
| Some(r) -> Console.WriteLine("Brian's favorite 32-bit integer is {0}", r)
| None -> ()
Здравствуйте, gandjustas, Вы писали:
G>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает.
В том то и дело, что для практических целей помимо самой монады важно то, как осуществляется выход из этой монады. Метод Process как раз и является безопасным выходом из монады в отличие от небезопасного GetValue.
Здравствуйте, IT, Вы писали:
IT>Я такой ПМ изобрёл у себя в Linq провайдере года два назад.
Я примерно тогда же.
IT>... Сегодня сделал бранч для рефакторинга, в том числе буду вычищать и это овно.
Но я еще не понял, что это говно . На что будешь его заменять? во что рефакторить?
Re[7]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
IT>>... Сегодня сделал бранч для рефакторинга, в том числе буду вычищать и это овно. AP>Но я еще не понял, что это говно .
Попробуй его в каком-нибудь навороченном высокорекурсивном алгоритме.
AP>На что будешь его заменять? во что рефакторить?
Пока не знаю. По ходу что-нибудь придумаем. Главное по-меньше лямбд и замыканий
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает. AP>В том то и дело, что для практических целей помимо самой монады важно то, как осуществляется выход из этой монады. Метод Process как раз и является безопасным выходом из монады в отличие от небезопасного GetValue.
Он полностью изоморфен паре Value\HasValue
AP>К тому же, выяснилось, что в нашем частном случае pattern-matching совпал с методом Process http://rsdn.ru/forum/design/3955158.1.aspx
Ну на самом деле не совпал, так как реализация Process может быть любая (сайд-эффекты и прочие гадости). А вот мой Process (надо переименовать в Match) и Option с двумя (строго) альтернативами как раз и является PM.
private static Option<IFollowingPublicationCalculator> GetByOtherNumber(string catalogNumber)
{
return from number in сatalogNumber.ToOption()
where number != string.Empty
from pub in FindPreviousPublicationIdByOtherNumber(number)
select new OtherNumberFollowingPublicationCalculator(pub, number)
as IFollowingPublicationCalculator;
}
private static Option<IFollowingPublicationCalculator> GetBySelfNumber(string catalogNumber, int releaseMark)
{
return from number in catalogNumber.ToOption()
where number != string.Empty
from pub in FindPreviousPublicationIdBySelfNumber(number, releaseMark)
select new SelfNumberFollowingPublicationCalculator(pub, number)
as IFollowingPublicationCalculator;
}
private static Optional<IFollowingPublicationCalculator> GetFollowingPublicationCalculator(
string catalogNumber, string precededCatalogNumber, int releaseMark)
{
var calc = GetByOtherNumber(precededCatalogNumber);
return calc.HasValue ? calc : GetBySelfNumber(catalogNumber, releaseMark);
}
Первые два метода вернут None если
1)catalogNumber равен null или пуст
2)метод Find возвращает null
3)Приведение типа не сработает
Если цель как раз описать вычисления, не думая о том что где-то может внезапно вернуться null, этот код полностью покрывает сценарии.
Re[15]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>Это ковариантность не нужна, ты до сих пор пример привести не смог даже. AP>Уже привел
. Ковариантность нужна .
Не-а. см выше.
G>>>>Любая реализация Option должна быть изоморфна любой другой. AP>>>Хватит уже пытаться подсунуть требования, которых нет! И которые не нужны. G>>... согласованность получения значение option и проверки наличия значения очень даже нужны. Просто потому что они в других библиотеках так сделаны. AP>Поведение моих реализаций согласовано с аналогичными реализациями в других библиотеках. Ты дописываешь свою реализацию, которую делаешь несогласованной с другими библиотеками. Почему претензии к результатам работы моего кода? Мой код делает ровно то, что заявлено, не больше, не меньше.
Претензии именно потому что я могу дописать такую реализацию.
G>>>>Любая реализация Option должна быть изоморфна любой другой. Иначе нарушаешь принцип наименьшего удивления. AP>>>Если я сделаю реализацию IComparer, который будет говорить что 3 больше 2. Отсортирую им массив. Как тут насчет принципа наименьшего удивления? G>>Не то сравниваешь. Тут вопрос согласованности, вот если ты сделаешь класс у которого не выполняется a.Equals(b) => a.GetHashCode() == b.GetHashCode(), то удивление будет ого-го, особенно при использовании в контейнерах. AP>Неплохая аналогия, да, тут надо делать согласованную реализацию двух методов. Аналогичные проблемы я отмечал для варианта, когда в интерфейсе IOptionalValue два свойства Value и HasValue. В моем коде у IOptionalValue метод один, поэтому согласовывать нечего.
не, у тебя метод Process обязан вызвать или один делегат или другой ровно один раз (там могут быть сайд-эффекты). Это гораздо более сильно условие чем согласованность двух методов.
Все было бы отлично, если бы не было возможности дописывать свои методы, но их дописывать можно. А вариант с Just\Some и None ничего дописывать не позволяет и контракт там не ломается.
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, IT, Вы писали:
IT>>>... Сегодня сделал бранч для рефакторинга, в том числе буду вычищать и это овно. AP>>Но я еще не понял, что это говно . IT>Попробуй его в каком-нибудь навороченном высокорекурсивном алгоритме.
У меня ровно обратный опыт. При свободном владении этими приемами достаточно запутанные (в том числе рекурсивные) алгоритмы надежно реализуются.
Однажды эти приемы кодирования помогли вывести сам алгоритм бизнес логики.
AP>>На что будешь его заменять? во что рефакторить? IT>Пока не знаю. По ходу что-нибудь придумаем. Главное по-меньше лямбд и замыканий
То есть хорошая замена еще даже не придумана, а реализованный, работающий live вариант назвали говном. Как-то не по-девелоперски это.
Сейчас уже поздно, и честно говоря, я бегло посмотрел твой код, и нифига не понял сакрального смысла, заложенного в нем. Возможно, смысл есть, завтра посмотрю повнимательнее. А пока тупой вопрос.
G>... Рефакторим так: ...
Зачем производим рефакторинг?
Re[9]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
IT>>Попробуй его в каком-нибудь навороченном высокорекурсивном алгоритме. AP>У меня ровно обратный опыт. При свободном владении этими приемами достаточно запутанные (в том числе рекурсивные) алгоритмы надежно реализуются.
У меня опыт ровно обоюдный. Есть вещи, которые таким способом реализуются не плохо, есть, которые, от применения такого паттерна сильно страдают. Как правило пока речь идёт о компактных задачах, всё нормально. В алгоритмах на несколько тысяч строк вреда становится существенно больше, чем пользы.
AP>Однажды эти приемы кодирования помогли вывести сам алгоритм бизнес логики.
Это без проблем. ФП вообще рулит, если его правильно дозировать.
AP>>>На что будешь его заменять? во что рефакторить? IT>>Пока не знаю. По ходу что-нибудь придумаем. Главное по-меньше лямбд и замыканий AP>То есть хорошая замена еще даже не придумана, а реализованный, работающий live вариант назвали говном. Как-то не по-девелоперски это.
Замена давно придума, качетсвенная и на порядки более мощная — ПМ. Непонятно, почему Хейльсберг и ко так сильно ей противится.
А эмуляция МП на лямбдах — да, извини, но это самое обыкновенное унылое овно. Поначалу немного вставляет, но быстро проходит.
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, IT, Вы писали:
IT>Или в Немерле. Но без ПМ этим пользоваться не очень удобно.
Функциональные программисты обычно делают Option/Maybe монадой и пользуются им соответственно, использовать его в паттерн-матчинге — вырожденный случай (который неплохо заменяется тренарным оператором и парой эксракторов, типа GetOrElse). http://en.wikipedia.org/wiki/Monad_(functional_programming)#Maybe_monad
//! Далее везде readNum возвращает Option-type
// Haskelldo
x <- readNum
y <- readNum
return $ x + y
// Scalafor {
x <- readNum()
y <- readNum()
} yield (x+y)
Так что надо определить для Option<T> Select, SelectMany, Where и пользоваться им из Linq:
from x in ReadNum()
from y in ReadNum()
select (x+y)
Re[7]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Ага, я уже догадался, что вы напишете такое. И с некоторым запозданием я добавил комментарий:
AP>Extract Method становится безопасным при использовании техники кодирования, описанной в разделе “Катастрофа при Extract Method”. http://rsdn.ru/forum/design/3955011.1.aspx
Вы его заметили? Полное описание техники кодирования в первом посте. Если в вкратце, то это: не использование “return null(схематичное обозначение)” + OptionalValue.
Я заметил. Но я наверное тупой — я вижу утверждение, но не вижу никаких его доказательств. В начале вы утверждаете, что в вашем подходе "компилируется — значит работает". Покажите мне, как спровоцировать ошибку компиляции при попытке вернуть null там, где нельзя.
AP>В абзаце выше уже написал, что OptionalValue в сочетании c не использованием “return null(схематичное обозначение)”.
Ах, с неиспользованием... Имхо, это изоморфно байке про порошок от вшей, который надо было каждой вши в глаза втирать. Если я не использую null, то безо всяких OptionalValue я получаю безопасный код.
AP>OptionalValue нацелен не напрямую на это. Его прямая цель -- реализация optional логики. Да, наверное, в заголовок лучше вынести последнее. Сейчас не самый удачный заголовок.
По-моему, проблема — не в заголовке. У вас и описание задачи совершенно никак не связано с предлагаемым решением.
Прямое решение проблемы, о которой вы говорите — строго противоположно. Это Mandatory<T>, который сразу падает при присваивании null. Оборудование всех мест, где нам нужен non-null, такими Mandatory<T> позволит нам гарантировать, что мы отловим момент записи null, а не чтения. Это, конечно, не так клёво, как ошибка компиляции, зато работает одинаково хорошо и для inline констант и для результатов вызовов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
AP>>В абзаце выше уже написал, что OptionalValue в сочетании c не использованием “return null(схематичное обозначение)”. S>Ах, с неиспользованием... Имхо, это изоморфно байке про порошок от вшей, который надо было каждой вши в глаза втирать.
Ага, а еще многие просто моются регулярно. А этот способ не дает 100% гарантии, вши все равно могут появиться.
AP>>... Его прямая цель -- реализация optional логики. ... S>Прямое решение проблемы, о которой вы говорите — строго противоположно. Это Mandatory<T>, который сразу падает при присваивании null.
Я про реализацию optional логики, выше выделил жирным. Причем тут присвоение null-ов?
AP>>OptionalValue нацелен не напрямую на это. Его прямая цель -- реализация optional логики. Да, наверное, в заголовок лучше вынести последнее. Сейчас не самый удачный заголовок. S>По-моему, проблема — не в заголовке. У вас и описание задачи совершенно никак не связано с предлагаемым решением. S>Прямое решение проблемы, о которой вы говорите — строго противоположно. Это Mandatory<T>, который сразу падает при присваивании null. Оборудование всех мест, где нам нужен non-null, такими Mandatory<T> позволит нам гарантировать, что мы отловим момент записи null, а не чтения. Это, конечно, не так клёво, как ошибка компиляции, зато работает одинаково хорошо и для inline констант и для результатов вызовов.
Что ваш Mandatory<T> предлагает для реализации optional логики? Передачу null-ов и “водопроводный” код, разобранный выше?
P.S. Кстати, OptionalValue можно сделать value типом. Но тогда, опять таки, теряем ковариантность. Надо подумать над этим выбором...
Re[5]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>>>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает. AP>>В том то и дело, что для практических целей помимо самой монады важно то, как осуществляется выход из этой монады. Метод Process как раз и является безопасным выходом из монады в отличие от небезопасного GetValue. G>Он полностью изоморфен паре Value\HasValue
В нем нет “throw new Exception()”. В методе GetValue есть. О какой изоморфности тут можно говорить?
G>private static Option<IFollowingPublicationCalculator> GetByOtherNumber(string catalogNumber)
G>{
G> return from number in сatalogNumber.ToOption()
G> where number != string.Empty
G> from pub in FindPreviousPublicationIdByOtherNumber(number)
G> select new OtherNumberFollowingPublicationCalculator(pub, number)
G> as IFollowingPublicationCalculator;
G>}
G>private static Option<IFollowingPublicationCalculator> GetBySelfNumber(string catalogNumber, int releaseMark)
G>{
G> return from number in catalogNumber.ToOption()
G> where number != string.Empty
G> from pub in FindPreviousPublicationIdBySelfNumber(number, releaseMark)
G> select new SelfNumberFollowingPublicationCalculator(pub, number)
G> as IFollowingPublicationCalculator;
G>}
G>private static Optional<IFollowingPublicationCalculator> GetFollowingPublicationCalculator(
G> string catalogNumber, string precededCatalogNumber, int releaseMark)
G>{
G> var calc = GetByOtherNumber(precededCatalogNumber);
G> return calc.HasValue ? calc : GetBySelfNumber(catalogNumber, releaseMark);
G>}
G>
G>Первые два метода вернут None если G>1)catalogNumber равен null или пуст G>2)метод Find возвращает null G>3)Приведение типа не сработает G>Если цель как раз описать вычисления, не думая о том что где-то может внезапно вернуться null, этот код полностью покрывает сценарии.
Ты это серьезно?!! Ты реально такое проделаешь с “живым” кодом? У меня все больше и больше сомнений в том, что ты действительно программируешь.
Ты можешь ответить, нафига ты это всё проделал?
Ручная работа с типами, о которой говорилось выше, выглядит так :
private static IOptionalValue<IFollowingPublicationCalculator> GetFollowingPublicationCalculator(
string catalogNumber, string precededCatalogNumber, int releaseMark)
{
if (string.IsNullOrEmpty(precededCatalogNumber))
{
return FindPreviousPublicationIdBySelfNumber(catalogNumber, releaseMark)
.ProcessValue<IFollowingPublicationCalculator>(value => new SelfNumberFollowingPublicationCalculator(value, catalogNumber));
}
else
{
return FindPreviousPublicationIdByOtherNumber(precededCatalogNumber)
.ProcessValue<IFollowingPublicationCalculator>(value => new OtherNumberFollowingPublicationCalculator(value, precededCatalogNumber));
}
}
Re[5]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
ANS>>Один или много объектов — это особенности реализации. См. Smalltalk, Objective-C. AP>А вот и нет. AP>Читаем статью по ссылке: AP>
AP>"[Одним из] недостатков является то, что паттерн 'Null Object' ... приводит к взрывному росту числа классов. Потому что необходимо создать свой 'пустой' класс для каждого абстрактного класса."
Имхо, это просто обобщение, которое возможно в силу более мощной платформы
AP>Я не знаком с Smalltalk и Objective-C, поэтому мне сложно оценить схожесть описанного в статье решения с OptionalValue. Но там идет речь о каком-то: AP>
AP>"Поедающий" сообщения nil
AP>OptionalValue ничего не поедает, поэтому, возможно, статья о другом.
Да, похоже то что ты предлагаешь никакого отношения `[Generalized ] Null Object` не имеет. Ты предлагаешь просто хак, который из null-не-объекта сделает null-объект. Дабы реализовать аналог управляющей конструкции ifNil:ifNotNil. Я уже писал, что это затея малополезная ввиду отсутствия нелокального возврата
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает. AP>>>В том то и дело, что для практических целей помимо самой монады важно то, как осуществляется выход из этой монады. Метод Process как раз и является безопасным выходом из монады в отличие от небезопасного GetValue. G>>Он полностью изоморфен паре Value\HasValue AP>В нем нет “throw new Exception()”. В методе GetValue есть. О какой изоморфности тут можно говорить?
Ты смысл слова "изоморфный" понимаешь?
Это наличие биективного преобразования. Изоморфные множества (категории) можно считать в некотором роде эквивалентными.
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Ты можешь ответить, нафига ты это всё проделал?
Чтобы показать что ни разу не нужен ни Proces, ни ковариантность. Причем покрывается гораздо более сложный случай частичных вычислений, чем в твоем коде.
ЗЫ. Ты так и не привел пример с получением данных из двух вебсервисов и отправкой третьему.
Re[7]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>>>>>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает. AP>>>>В том то и дело, что для практических целей помимо самой монады важно то, как осуществляется выход из этой монады. Метод Process как раз и является безопасным выходом из монады в отличие от небезопасного GetValue. G>>>Он полностью изоморфен паре Value\HasValue AP>>В нем нет “throw new Exception()”. В методе GetValue есть. О какой изоморфности тут можно говорить? G>Ты смысл слова "изоморфный" понимаешь? G>Это наличие биективного преобразования. Изоморфные множества (категории) можно считать в некотором роде эквивалентными.
Да. В нашем случае такого преобразования нет.
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>>>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает. AP>>>>>В том то и дело, что для практических целей помимо самой монады важно то, как осуществляется выход из этой монады. Метод Process как раз и является безопасным выходом из монады в отличие от небезопасного GetValue. G>>>>Он полностью изоморфен паре Value\HasValue AP>>>В нем нет “throw new Exception()”. В методе GetValue есть. О какой изоморфности тут можно говорить? G>>Ты смысл слова "изоморфный" понимаешь? G>>Это наличие биективного преобразования. Изоморфные множества (категории) можно считать в некотором роде эквивалентными. AP>Да. В нашем случае такого преобразования нет.
То есть ты хочешь сказать что из одного Process нельзя сделать пару Value\HasValue, а из этой пары нельзя сделать Process?
Вообще-то код доказывает обратное.
Но вот с твои IOptionalValue можно подсунуть реализацию, которая эту самую биективность нарушает и это очень плохо, потому что любой пользователь будет изначально рассчитывать именно на биективность.
Re[6]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Да, похоже то что ты предлагаешь никакого отношения `[Generalized ] Null Object` не имеет. Ты предлагаешь просто хак, который из null-не-объекта сделает null-объект. Дабы реализовать аналог управляющей конструкции ifNil:ifNotNil. Я уже писал, что это затея малополезная ввиду отсутствия нелокального возврата
.
Да, фича прикольная. И была бы полезна для анонимных делегатов. Но поскольку в хорошем коде даже в обычных методах “return” в середине метода не очень часто встречается, поэтому потребность в нелокальном возврате довольно низкая.
И уж тем более отсутствие этой фичи не сильно влияет на полезность OptionalValue.
Re[9]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Я про реализацию optional логики, выше выделил жирным. Причем тут присвоение null-ов?
Если вы про реализацию optional логики, то и пишите про реализацию optional логики. И приводите примеры про реализацию optional логики.
А вы сначала пишете про "избавиться от null", и про "безопасность Extract Method". Потом резко переходите к некоему решению, безо всякой логической связи с избавлением от null-ов и Extract Method.
Убедительного примера про optional логику я тоже не вижу. Пример с method1().method2().method3() прекрасно работает безо всякого OptionalValue.
AP>Что ваш Mandatory<T> предлагает для реализации optional логики? Передачу null-ов и “водопроводный” код, разобранный выше?
Для optional логики он предлагает передачу null-ов. На водопроводном коде он не настаивает. К примеру, вполне будет работать вот такой код:
var x = Method1()
.ProcessValue(_ => _.Method2())
.ProcessValue(_ => _.Method3())
.ProcessValue(_ => _.Method4());
Зачем здесь OptionalValue?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: Optional Value. Уменьшение количества null reference
Здравствуйте, Sinclair, Вы писали:
S>>Если вы про реализацию optional логики, то и пишите про реализацию optional логики. И приводите примеры про реализацию optional логики.
Да, я уже отметил, что акцент в первую очередь надо было сделать на реализации optional логики. Это была моя ошибка. Но форум как раз и служит для такого рода диалога.
Сейчас я пришел к тому, что акцент надо делать просто на передачу необязательных значений между разными scope-ами: между методами, внутри одного метода и т.п. Показать, что OptionalValue предлагает безопасный способ передачи значений между scope-ами.
S>>А вы сначала пишете про "избавиться от null", и про "безопасность Extract Method". Потом резко переходите к некоему решению, безо всякой логической связи с избавлением от null-ов и Extract Method.
Опишите полную картину для вашей реализации через Mandatory<T>, и, возможно, увидите связи и в моем описании. Например, см. мой вопрос ниже. Но в целом, да, согласен, описание надо переделать.
AP>>>Что ваш Mandatory<T> предлагает для реализации optional логики? Передачу null-ов и “водопроводный” код, разобранный выше? S>>Для optional логики он предлагает передачу null-ов. На водопроводном коде он не настаивает. К примеру, вполне будет работать вот такой код: S>>
S>>Зачем здесь OptionalValue?
Про это я уже отписался тут:
S>>Но самое что интересное, для такой записи не нужны OptionalValue<T>.
Ага, я это знаю . Только остается вопрос, когда такой записью пользоваться? Для всех переменных? Нет, спасибо, не буду.
OptionalValue как раз и служит для разделение опциональных и не опциональных переменных. Соответственно, для первых применяем такую запись, а для вторых обычную. А какой будет переменная T или IOptionalValue<T> определяет поставщик переменной. Если мы знаем, что поставщик соблюдает это правило, то для T можно не беспокоиться об NRE. Если поставщик не соблюдает это правило, то все как обычно, т.е. хреново: писать или не писать if, если писать, то, что внутри этого if-а делать и т.д. Глупость заключается в том, чтобы создавать эту хреновую ситуацию и в случае, если вы сами являетесь тем поставщиком. http://www.rsdn.ru/forum/design/3954267.1.aspx
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Сейчас я пришел к тому, что акцент надо делать просто на передачу необязательных значений между разными scope-ами: между методами, внутри одного метода и т.п. Показать, что OptionalValue предлагает безопасный способ передачи значений между scope-ами.
Покажите. Пока что я этого не вижу. Семантика OptionalValue — точно такая же, как и в случае обычного T:class.
AP>Опишите полную картину для вашей реализации через Mandatory<T>, и, возможно, увидите связи и в моем описании.
Я не понимаю что такое "полная картина". Для того, чтобы приведённый код c ProcessValue заработал, достаточно написать один тривиальный extension method. Вам его привести?
AP>Ага, я это знаю . Только остается вопрос, когда такой записью пользоваться? Для всех переменных? Нет, спасибо, не буду.
Почему для всех? Только для optional. Во всех остальных местах меняйте на Mandatory<> и наслаждайтесь.
AP>OptionalValue как раз и служит для разделение опциональных и не опциональных переменных. Соответственно, для первых применяем такую запись, а для вторых обычную. А какой будет переменная T или IOptionalValue<T> определяет поставщик переменной. Если мы знаем, что поставщик соблюдает это правило, то для T можно не беспокоиться об NRE. Если поставщик не соблюдает это правило, то все как обычно, т.е. хреново: писать или не писать if, если писать, то, что внутри этого if-а делать и т.д. Глупость заключается в том, чтобы создавать эту хреновую ситуацию и в случае, если вы сами являетесь тем поставщиком. AP>http://www.rsdn.ru/forum/design/3954267.1.aspx
AP>[/q]
AP>Вы будете писать везде “a1.ProcessValue(_ => _.SomeMethod())”, где источник (переменная “a1”) не Mandatory<T>? Вы это предлагаете?
Совершенно верно. По крайней мере, нам не нужно гадать, соблюдает поставщик правила или нет. В вашем случае совершенно невозможно понять, случайно или намеренно был опущен ProcessValue.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[12]: Optional Value. Уменьшение количества null reference
Здравствуйте, Sinclair, Вы писали:
AP>>Сейчас я пришел к тому, что акцент надо делать просто на передачу необязательных значений между разными scope-ами: между методами, внутри одного метода и т.п. Показать, что OptionalValue предлагает безопасный способ передачи значений между scope-ами. S>Покажите. Пока что я этого не вижу. Семантика OptionalValue — точно такая же, как и в случае обычного T:class.
Ok, продемонстрирую безопасный способ передачи необязательного значения между разными scope-ами. Допустим, мы можем получить некоторое значение “var value = ...” только при определенном условии “someCondition”. Причем получение значения происходит в одном скоупе Scope1, а использование в другом Scope2. Пишем вот такой код:
Type1 outerValue;
#region Scope1
if (someCondition)
{
var value = ...
outerValue = value;
}
#endregion End of Scope1
#region Scope2
Console.WriteLine(outerValue.Name);
#endregion End of Scope2
Упс, строка “Console.WriteLine(outerValue.Name)” не компилируется:
Error 1 Use of unassigned local variable 'outerValue'
Что же делать? Если написать:
if (someCondition)
{
var value = ...
outerValue = value;
}
else
{
outerValue = null;
}
то получим NRE в Scope2.
Вспоминаем, что есть Nothing. Пишем его:
if (someCondition)
{
var value = ...;
outerValue = value;
}
else
{
outerValue = OptionalValue.Nothing<Type1>();
}
Не компилируется. Меняем тип переменной outerValue на IOptionalValue<Type1>:
IOptionalValue<Type1> outerValue;
#region Scope1
if (someCondition)
{
var value = ...
outerValue = value.AsOptionalValue();
}
else
{
outerValue = OptionalValue.Nothing<Type1>();
}
#endregion End of Scope1
#region Scope2
Console.WriteLine(outerValue.Name);
#endregion End of Scope2
Теперь не компилируется Scope2 (строка “outerValue.Name”). Для работы с IOptionalValue переменными используется метод Process. Используем его.
IOptionalValue<Type1> outerValue;
#region Scope1
if (someCondition)
{
var value = ...;
outerValue = value.AsOptionalValue();
}
else
{
outerValue = OptionalValue.Nothing<Type1>();
}
#endregion End of Scope1
#region Scope2
outerValue.Process(
value => Console.WriteLine(value.Name)
);
#endregion End of Scope2
Опять не компилируется. Метод Process требует второй аргумент. Ставим TODO.
IOptionalValue<Type1> outerValue;
#region Scope1
if (someCondition)
{
var value = ...;
outerValue = value.AsOptionalValue();
}
else
{
outerValue = OptionalValue.Nothing<Type1>();
}
#endregion End of Scope1
#region Scope2
outerValue.Process(
value => Console.WriteLine(value.Name),
() =>
{
//TODO: implement thisthrow new NotImplementedException();
}
);
#endregion End of Scope2
Далее думаем, ..., смотрим документы с требованиями к продукту, по необходимости общаемся с бизнес-аналитиком, заказчиком и т.д. В результате этого процесса получаем ответ на вопрос, что делать в случае, помеченном TODO. И реализуем это TODO.
С этого момента OptionalValue я позиционирую как безопасный способ передачи необязательного значения между разными scope-ами. Темы упомянутые ранее:
уменьшение количества null-ов,
optional логика
не являются первичными.
Относительно Mandatory<T> отпишусь чуть позже. ... Если кратко, то на практике это не пойдет.
Re[13]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, Sinclair, Вы писали:
AP>>>Сейчас я пришел к тому, что акцент надо делать просто на передачу необязательных значений между разными scope-ами: между методами, внутри одного метода и т.п. Показать, что OptionalValue предлагает безопасный способ передачи значений между scope-ами. S>>Покажите. Пока что я этого не вижу. Семантика OptionalValue — точно такая же, как и в случае обычного T:class. AP>Ok, продемонстрирую безопасный способ передачи необязательного значения между разными scope-ами. Допустим, мы можем получить некоторое значение “var value = ...” только при определенном условии “someCondition”. Причем получение значения происходит в одном скоупе Scope1, а использование в другом Scope2. Пишем вот такой код:
AP>Type1 outerValue;
AP>#region Scope1
AP>if (someCondition)
AP>{
AP> var value = ...
AP> outerValue = value;
AP>}
AP>#endregion End of Scope1
AP>#region Scope2
AP>Console.WriteLine(outerValue.Name);
AP>#endregion End of Scope2
AP>
Упс, строка “Console.WriteLine(outerValue.Name)” не компилируется: AP>
AP>Error 1 Use of unassigned local variable 'outerValue'
Что же делать? Если написать:
А чего бы не написать
if (someCondition)
{
var value = ...
Console.WriteLine(outerValue.Name);
}
???
Re[14]: Optional Value. Уменьшение количества null reference
Здравствуйте, Sinclair, Вы писали:
AP>>Опишите полную картину для вашей реализации через Mandatory<T>, и, возможно, увидите связи и в моем описании. S>Я не понимаю что такое "полная картина". Для того, чтобы приведённый код c ProcessValue заработал, достаточно написать один тривиальный extension method. Вам его привести?
Его уже приводили в этом треде. Я такое писал (на другом форуме) еще года 4 назад.
AP>>Опишите полную картину для вашей реализации через Mandatory<T>, и, возможно, увидите связи и в моем описании. S>Я не понимаю что такое "полная картина". S>... AP>>Ага, я это знаю . Только остается вопрос, когда такой записью пользоваться? Для всех переменных? Нет, спасибо, не буду. S>Почему для всех? Только для optional. Во всех остальных местах меняйте на Mandatory<> и наслаждайтесь.
В прошлом сообщении
я написал, что Mandatory<T> не будет работать на практике. Теперь прокомментирую свой вывод. Я думаю, что проще всего это показать, разобрав несколько секунд из жизни программиста и кода.
Сейчас программист пишет вот так:
new SomeClass1().SomeMethod1();
Выделяем некоторый кусок кода (например, “new SomeClass1()”) и наживаем “Extract Method”:
В результате получаем:
Здравствуйте, gandjustas, Вы писали:
G>>>А чего бы не написать G>>>
G>>> ...
G>>>
G>>>??? AP>>В рамках рассматриваемого примера это по условию задачи:
AP>>Ok, продемонстрирую безопасный способ передачи необязательного значения между разными scope-ами.
AP>>Пример демонстрирует возможности инструмента. G>Надо подходить со стороны решения задачи, а не демонстрации возможностей на выдуманом примере.
Именно так ! В задаче четко прописано некоторое условие, ты его пытаешься отбросить и формулируешь другую задачу.
G>Если рассмотреть твою задачу: надо выполнить разные действия в зависимости от условия. Это решается банальным if-ом.
Это другая задача. Ты уже не первый раз меняешь задачу под свое виденье решения, иногда такой подход бывает полезным, но если им злоупотреблять, то человека просто увольняют, поскольку он уже всех достал.
В моем примере разделение на scope-ы, например, позволяет вынести любой scope в отдельный метод.
Re[17]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>А чего бы не написать G>>>>
G>>>> ...
G>>>>
G>>>>??? AP>>>В рамках рассматриваемого примера это по условию задачи:
AP>>>Ok, продемонстрирую безопасный способ передачи необязательного значения между разными scope-ами.
AP>>>Пример демонстрирует возможности инструмента. G>>Надо подходить со стороны решения задачи, а не демонстрации возможностей на выдуманом примере. AP>Именно так ! В задаче четко прописано некоторое условие, ты его пытаешься отбросить и формулируешь другую задачу.
Нет, я именно формулирую задачу, а ты приводишь детали реализации, относящиеся непонятно к чему.
G>>Если рассмотреть твою задачу: надо выполнить разные действия в зависимости от условия. Это решается банальным if-ом. AP>Это другая задача. Ты уже не первый раз меняешь задачу под свое виденье решения, иногда такой подход бывает полезным, но если им злоупотреблять, то человека просто увольняют, поскольку он уже всех достал.
AP>В моем примере разделение на scope-ы, например, позволяет вынести любой scope в отдельный метод.
Только ты не написал для чего тебе разные скоупы, те банально высосал проблему из пальца.
Re[13]: Optional Value. Уменьшение количества null reference
AP>Вы можете описать подробно step by step рассмотренные несколько секунд из жизни программиста и кода при применении Mandatory?
Могу, только без скриншотов.
1. программист пишет вот так:
SomeClass1.New().Value.SomeMethod1()
2. Выделяем SomeClass1.New() и нажимаем Extract Method
3. В результате получаем:
Здравствуйте, Sinclair, Вы писали:
S>Могу, только без скриншотов.
Да, то что нужно.
S>1. программист пишет вот так: S>
S>SomeClass1.New().Value.SomeMethod1()
S>
Таким образом, вы подменяете стандартную для языка процедуру -- вызов публичного конструктора во внешнем коде. Тут требуется формулировка правила/полиси/конвеншена для повсеместного применения. Когда? Где? Зачем? делать такую подмену?
В рамках рассматриваемого примера мы получили усложнение в чистом виде, а выгода нулевая.
Re[15]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
S>>1. программист пишет вот так: S>>
S>>SomeClass1.New().Value.SomeMethod1()
S>>
AP>Таким образом, вы подменяете стандартную для языка процедуру -- вызов публичного конструктора во внешнем коде. Тут требуется формулировка правила/полиси/конвеншена для повсеместного применения. Когда? Где? Зачем? делать такую подмену?
Для решения проблемы "избавление от null".
В жизни, конечно же, ваш синтетический пример не встречается. Если программист делает вызов на анонимном объекте, то он практически никогда в жизни не будет делать Extract Method и проблема абсолютно надумана.
А как только у нас появляется именованный объект, у нас появляется возможность указать любую policy с точно такими же затратами, как в вашем случае. То есть во всяком месте, где у нас требуется гарантия наличия значения, мы пишем Mandatory<T> и всё.
AP>В рамках рассматриваемого примера мы получили усложнение в чистом виде, а выгода нулевая.
Ну покажите теперь ваш же пример с IOptionalValue. И посмотрим, у кого усложнение.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Optional Value. Уменьшение количества null reference
Здравствуйте, gandjustas, Вы писали:
G>>>>>А чего бы не написать G>>>>>
G>>>>> ...
G>>>>>
G>>>>>??? AP>>>>В рамках рассматриваемого примера это по условию задачи:
AP>>>>Ok, продемонстрирую безопасный способ передачи необязательного значения между разными scope-ами.
AP>>>>Пример демонстрирует возможности инструмента. G>>>Надо подходить со стороны решения задачи, а не демонстрации возможностей на выдуманом примере. AP>>Именно так ! В задаче четко прописано некоторое условие, ты его пытаешься отбросить и формулируешь другую задачу. G>Нет, я именно формулирую задачу, а ты приводишь детали реализации, относящиеся непонятно к чему.
Открываем мой пост
. В начале идет четкая формулировка задачи. Затем ее реализация. Какие детали реализации ты не можешь связать с условием задачи?
AP>>В моем примере разделение на scope-ы, например, позволяет вынести любой scope в отдельный метод. G>Только ты не написал для чего тебе разные скоупы, те банально высосал проблему из пальца.
Практикующий программист понимает, что scope-ы могут понадобиться для различных целей: для выделения в отдельные методы, для использования внутри охватывающего using-а и т.п. Поэтому писать для чего нужны скоупы это загромождать пример лишними атрибутами.
Re[19]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>>>А чего бы не написать G>>>>>>
G>>>>>> ...
G>>>>>>
G>>>>>>??? AP>>>>>В рамках рассматриваемого примера это по условию задачи:
AP>>>>>Ok, продемонстрирую безопасный способ передачи необязательного значения между разными scope-ами.
AP>>>>>Пример демонстрирует возможности инструмента. G>>>>Надо подходить со стороны решения задачи, а не демонстрации возможностей на выдуманом примере. AP>>>Именно так ! В задаче четко прописано некоторое условие, ты его пытаешься отбросить и формулируешь другую задачу. G>>Нет, я именно формулирую задачу, а ты приводишь детали реализации, относящиеся непонятно к чему. AP>Открываем мой пост
. В начале идет четкая формулировка задачи. Затем ее реализация. Какие детали реализации ты не можешь связать с условием задачи?
безопасный способ передачи необязательного значения между разными scope-ами
Ты считаешь это формулировкой задачи?
Хотя бы опиши какое поведение должно наблюдаться.
AP>>>В моем примере разделение на scope-ы, например, позволяет вынести любой scope в отдельный метод. G>>Только ты не написал для чего тебе разные скоупы, те банально высосал проблему из пальца. AP>Практикующий программист понимает, что scope-ы могут понадобиться для различных целей: для выделения в отдельные методы, для использования внутри охватывающего using-а и т.п. Поэтому писать для чего нужны скоупы это загромождать пример лишними атрибутами.
Практикующий программист понимает что разные скоупы можно свести к одному и не плодить сущности без нужды.
Приведи пример задачи где эти скоупы необходимы. Ты же "Практикующий программист", у тебя должно быть много таких примеров.
Re[16]: Optional Value. Уменьшение количества null reference
Здравствуйте, Sinclair, Вы писали:
AP>>Таким образом, вы подменяете стандартную для языка процедуру -- вызов публичного конструктора во внешнем коде. Тут требуется формулировка правила/полиси/конвеншена для повсеместного применения. Когда? Где? Зачем? делать такую подмену? S>Для решения проблемы "избавление от null".
Замечу, что в этом треде такая задача ни разу не ставилась.
AP>>Таким образом, вы подменяете стандартную для языка процедуру -- вызов публичного конструктора во внешнем коде. Тут требуется формулировка правила/полиси/конвеншена для повсеместного применения. Когда? Где? Зачем? делать такую подмену? S>Для решения проблемы "избавление от null". S>В жизни, конечно же, ваш синтетический пример не встречается. Если программист делает вызов на анонимном объекте, то он практически никогда в жизни не будет делать Extract Method и проблема абсолютно надумана. S>А как только у нас появляется именованный объект, у нас появляется возможность указать любую policy с точно такими же затратами, как в вашем случае. То есть во всяком месте, где у нас требуется гарантия наличия значения, мы пишем Mandatory<T> и всё.
Во-первых, причем тут Extract Method, мои вопросы, на которые вы отвечали, касались исключительно первой строки в вашем коде. Или в вашем коде второй пункт оказывает влияние на первую строчку? Если так, то это совсем хреново.
Во-вторых, если первую строчку в моем примере написать вот так:
var someClass1 = new SomeClass1();
someClass1.SomeMethod1();
Это что-то принципиально поменяет? Если да, то распишите step by step и этот вариант.
AP>>В рамках рассматриваемого примера мы получили усложнение в чистом виде, а выгода нулевая. S>Ну покажите теперь ваш же пример с IOptionalValue. И посмотрим, у кого усложнение.
В текущем примере нет необязательных значений, поэтому код примера остается неизменным.
S>... с точно такими же затратами, как в вашем случае. ...
Рассматриваемый пример показал обратное: у меня затраты нулевые, у вас ненулевые.
Сделаю некоторый комментарий относительно OptionalValue. Главный ресурс, который стоит экономить, это умственные усилия программиста. При использовании OptionalValue программисту нет необходимости задумываться над расстановкой T или IOptionalValue<T>, фактически это делается под однозначным управлением со стороны компилятора или ReSharper-а. Всё начинается с того, что в одной из веток кода у нас нет подходящего значения для возврата, тогда мы пишем Nothing. А далее компилятор (или ReSharper) нас ведет “за руку” по однозначному пути. Пример такого процесса был продемонстрирован тут
Здравствуйте, Alexander Polyakov, Вы писали:
S>>А как только у нас появляется именованный объект, у нас появляется возможность указать любую policy с точно такими же затратами, как в вашем случае. То есть во всяком месте, где у нас требуется гарантия наличия значения, мы пишем Mandatory<T> и всё. AP>Во-первых, причем тут Extract Method, мои вопросы, на которые вы отвечали, касались исключительно первой строки в вашем коде.
А мне казалось, что Extract Method является неотъемлемой частью вашей задачи. Если нет — дайте другой пример, без Extract Method.
AP>Во-вторых, если первую строчку в моем примере написать вот так:
AP>var someClass1 = new SomeClass1();
AP>someClass1.SomeMethod1();
AP>
Это что-то принципиально поменяет? Если да, то распишите step by step и этот вариант.
Конечно поменяет. Как только нам потребуется гарантия невылета null при использовании, мы заменим var на Mandatory<SomeClass1>. А дальше всё сделает компилятор и среда.
S>>Ну покажите теперь ваш же пример с IOptionalValue. И посмотрим, у кого усложнение. AP>В текущем примере нет необязательных значений, поэтому код примера остается неизменным.
А как же "катастрофа с null", которую кто-то так красочно расписывал неделю назад? AP>Рассматриваемый пример показал обратное: у меня затраты нулевые, у вас ненулевые.
Ну, если вот так передёргивать, то всегда можно показать обратное.
AP>Сделаю некоторый комментарий относительно OptionalValue. Главный ресурс, который стоит экономить, это умственные усилия программиста. При использовании OptionalValue программисту нет необходимости задумываться над расстановкой T или IOptionalValue<T>, фактически это делается под однозначным управлением со стороны компилятора или ReSharper-а. Всё начинается с того, что в одной из веток кода у нас нет подходящего значения для возврата, тогда мы пишем Nothing. А далее компилятор (или ReSharper) нас ведет “за руку” по однозначному пути. Пример такого процесса был продемонстрирован тут
.
Интересная гипотеза. Неплохо бы как-то обосновать то, что источником заметного процента null-ов у нас является "отсутствие подходящего значения". Потому что в моём опыте гораздо чаще происходит неявное присваивание null. Например, как-то так:
var settings = new SomeSettings();
if (someCondition)
settings.Loader = new FileLoader();
...
settings.Loader.Load(fileName);
Здесь при невыполнении условия Loader останется проинициализированным по умолчанию. И мы имеем настоящую, а не воображаемую, катастрофу с null. Отладка её особенно неприятна потому, что строчка с Loader.Load может встретиться где угодно — совершенно не в том методе, где была совершена ошибка. Объявление Loader как Mandatory<ILoader> позволяет мне гарантировать, что никаких null там не будет.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[18]: Optional Value. Уменьшение количества null reference
Здравствуйте, Sinclair, Вы писали:
S>>>А как только у нас появляется именованный объект, у нас появляется возможность указать любую policy с точно такими же затратами, как в вашем случае. То есть во всяком месте, где у нас требуется гарантия наличия значения, мы пишем Mandatory<T> и всё. AP>>Во-первых, причем тут Extract Method, мои вопросы, на которые вы отвечали, касались исключительно первой строки в вашем коде. S>А мне казалось, что Extract Method является неотъемлемой частью вашей задачи. Если нет — дайте другой пример, без Extract Method.
Мой пример являлся только отправной точкой, и он прекрасно выполнил свою роль. Пример выявил, что вместо вызова публичного конструктора во внешнем коде вы предлагаете писать статический метод New(). Я прошу у вас сформулировать и обосновать policy для повсеместного использования этого подхода. Или у вас нет policy на счет замены конструктора на New()?
Кстати, как будут выглядеть ваш код и policy, если нет возможности дописывать статические методы, например, при использовании конструкторов классов из .Net Framework-а?
S>... мы заменим var на Mandatory<SomeClass1> ...
Ага, теперь уже и “var” нельзя использовать. И наш язык программирования начинает помаленьку рассыпаться.
S>... Как только нам потребуется гарантия невылета null при использовании ...
Странное предложение. Если логика задачи такова, что во всех ветках существует нормальное значение для возврата, то, естественно, хочется иметь такую гарантию ВСЕГДА (если гарантия не очень дорого стоит). То есть определяющей точкой служит наличие нормальных значений, а не потребность в какой-то гарантии.
S>А как же "катастрофа с null", которую кто-то так красочно расписывал неделю назад?
У меня было “Катастрофа при Extract Method”, “уменьшение количества null reference-ов”. “Катастрофы с null” не было. О каком красочном описании вы говорите? Все ходы записаны, можете перечитать.
В принципе, описание в первом посте получилось не очень удачным, но чего не было, того не было.
AP>>Рассматриваемый пример показал обратное: у меня затраты нулевые, у вас ненулевые. S>Ну, если вот так передёргивать, то всегда можно показать обратное.
Это не передергивание. А всего лишь демонстрация на примере того, что у вашего подхода с Mandatory<T> нет прямого обоснования. Есть только косвенное обоснование. А такие приемы и policy плохо приживаются на практике.
S>Интересная гипотеза. Неплохо бы как-то обосновать то, что источником заметного процента null-ов у нас является "отсутствие подходящего значения". Потому что в моём опыте гораздо чаще происходит неявное присваивание null. Например, как-то так: S>
S>var settings = new SomeSettings();
S>if (someCondition)
S> settings.Loader = new FileLoader();
S>...
S>settings.Loader.Load(fileName);
S>
S>Здесь при невыполнении условия Loader останется проинициализированным по умолчанию. И мы имеем настоящую, а не воображаемую, катастрофу с null. Отладка её особенно неприятна потому, что строчка с Loader.Load может встретиться где угодно — совершенно не в том методе, где была совершена ошибка. Объявление Loader как Mandatory<ILoader> позволяет мне гарантировать, что никаких null там не будет.
Отмечу, что кое-что на этот счет я писал в первом посте:
Все null-ы мы таким образом не истребим, поскольку
a. field-ы классов инициализируются null-ами,
b. оператор "as" возвращает null,
c. уже имеющиеся библиотеки поставляют null-ы.
Но наша цель более скромная – уменьшить количество null-ов. Кстати, по пунктам a и b еще можно кое-что отвоевать. http://rsdn.ru/forum/design/3952383.flat.aspx
S>Интересная гипотеза. Неплохо бы как-то обосновать то, что источником заметного процента null-ов у нас является "отсутствие подходящего значения". Потому что в моём опыте гораздо чаще происходит неявное присваивание null. Например, как-то так: S>
S>var settings = new SomeSettings();
S>if (someCondition)
S> settings.Loader = new FileLoader();
S>...
S>settings.Loader.Load(fileName);
S>
S>Здесь при невыполнении условия Loader останется проинициализированным по умолчанию. И мы имеем настоящую, а не воображаемую, катастрофу с null.
Во-первых, этот процент зависит от стиля кодирования. Например, я в последние годы стараюсь как можно реже использовать не readonly состояние. В вашем примере “settings.Loader” это изменяемое состояние. Изменяемое состояние приводит к гораздо более широкому кругу проблем, чем null-ы.
Во-вторых, процент зависит от задачи.
Учитывая эти замечания, я думаю, что оценкой этого процента надо заниматься в рамках конкретного проекта. Я лишь предлагаю инструмент, а выбирать между различными вариантами вам. По моему опыту OptionalValue достаточно востребованная вещь, мы используем его в своих проектах. OptionalValue лежит себе никому не мешает, есть не просит, к нему обращаются только, если появилась ситуация, когда нет нормального значения для возврата. И в этом случае OptionalValue нам верно служит, делая работу с такой ситуацией безопасной.
S>Здесь при невыполнении условия Loader останется проинициализированным по умолчанию. ... Объявление Loader как Mandatory<ILoader> позволяет мне гарантировать, что никаких null там не будет.
Как Mandatory спасет от null-ов, которые появляются при инициализации по умолчанию? Продемонстрируйте строчками кода.
Re[19]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
S>>... мы заменим var на Mandatory<SomeClass1> ... AP>Ага, теперь уже и “var” нельзя использовать.
Можно, отчего же. Если вам удобнее, то пишите
var x = (new SomeClass1).AsMandatory();
S>>А как же "катастрофа с null", которую кто-то так красочно расписывал неделю назад? AP>У меня было “Катастрофа при Extract Method”, “уменьшение количества null reference-ов”. “Катастрофы с null” не было. О каком красочном описании вы говорите?
См. топикстарт.
AP>Это не передергивание. А всего лишь демонстрация на примере того, что у вашего подхода с Mandatory<T> нет прямого обоснования. Есть только косвенное обоснование. А такие приемы и policy плохо приживаются на практике.
Возможно.
AP>Во-первых, этот процент зависит от стиля кодирования. Например, я в последние годы стараюсь как можно реже использовать не readonly состояние. В вашем примере “settings.Loader” это изменяемое состояние. Изменяемое состояние приводит к гораздо более широкому кругу проблем, чем null-ы.
Да, возможно. Допускаю, что использование OptionalValue в проектах с функциональным стилем может быть оправдано. Т.к. null вызывает проблемы в основном при изменяемом состоянии. Если состояние неизменяемое, то найти того, кто отдал null, нетрудно.
AP>Как Mandatory спасет от null-ов, которые появляются при инициализации по умолчанию? Продемонстрируйте строчками кода.
Надо подумать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Optional Value. Уменьшение количества null reference-
Да, именно. Уверен, многие делали подобные хелперы. В моем похожем варианте базовым был интерфейс, а два реализатора на struct, что в случаях, доступных компилятору, делает всё на один уровень косвенности меньше.
Re[10]: Optional Value. Уменьшение количества null reference
Здравствуйте, IT, Вы писали:
IT>>>Попробуй его в каком-нибудь навороченном высокорекурсивном алгоритме. AP>>У меня ровно обратный опыт. При свободном владении этими приемами достаточно запутанные (в том числе рекурсивные) алгоритмы надежно реализуются. IT>У меня опыт ровно обоюдный. Есть вещи, которые таким способом реализуются не плохо, есть, которые, от применения такого паттерна сильно страдают. Как правило пока речь идёт о компактных задачах, всё нормально. В алгоритмах на несколько тысяч строк вреда становится существенно больше, чем пользы.
Во-первых, я специально написал “при свободном владении этими приемами”. Это подразумевает понимание границ применимости этой техники.
? Сравнение пользы и вреда какого-либо подхода производят, когда есть некоторый известный эталонный вариант реализации; именно от этого эталонного варианта отсчитывают пользу и вред. Т.е. ты оперируешь величинами, не имея точки отсчета для этих величин. В общем, эти твои рассуждения -- чушь.
IT>... Как правило пока речь идёт о компактных задачах, всё нормально. В алгоритмах на несколько тысяч строк вреда становится существенно больше, чем пользы.
Техника является низкоуровневым приемом кодирования, поэтому соотношение между ее достоинствами и недостатками видно уже на небольших кусках кода. Очень сомнительно, что соотношение между достоинствами и недостатками меняется при росте количества строк (я такого не наблюдал).
AP>>>>На что будешь его заменять? во что рефакторить? IT>>>Пока не знаю. По ходу что-нибудь придумаем. Главное по-меньше лямбд и замыканий AP>>То есть хорошая замена еще даже не придумана, а реализованный, работающий live вариант назвали говном. Как-то не по-девелоперски это. IT>Замена давно придума, качетсвенная и на порядки более мощная — ПМ. Непонятно, почему Хейльсберг и ко так сильно ей противится.
Эээ, что-то ты спрыгиваешь с контекста разговора. Ты пишешь, что сделал бранч для рефакторинга, я спрашиваю, на что заменять будешь. В моем последнем предложении слово “замена” именно в контексте твоего рефакторинга. Причем тут замена в виде ПМ? Нет у тебя замены в рамках C# 4.0, так и напиши, зачем юлить?
IT>Замена давно придума, качетсвенная и на порядки более мощная — ПМ. Непонятно, почему Хейльсберг и ко так сильно ей противится. IT>А эмуляция МП на лямбдах — да, извини, но это самое обыкновенное унылое овно. Поначалу немного вставляет, но быстро проходит.
Я не сомневаюсь, что ПМ замечательная вещь, и что с его помощью тоже можно решить рассматриваемую задачу. Но суть в том, что для рассматриваемой задачи решения через ПМ и без него являются одинаковыми, совпадение решений почти посимвольное
Как насчет ковариантности по generic параметру при реализации через ПМ? Потребуется ковариантность классов, а этого сейчас опять таки нет в языке.
Какой вариант решения через ПМ ты хочешь: через discriminated union или через type check? Если через discriminated union, то опять таки надо расширять язык дополнительной конструкцией. Если через type check, то вместо простого “x”, значение надо получать через обращение к свойству “x.Value”.
В общем, у нас уже есть решение, которое, во-первых, не требует расширений языка, а, во-вторых, ни в чем не уступает варианту через ПМ. Поэтому рассмотрение ПМ в рамках данного треда становится неуместным.
Re: Optional Value. Уменьшение количества null reference-ов.
Покажи пожалуйста на примере, как твоя идея будет работать.
Цепочка что я привел, может быть в несколько раз длиннее и в ней где попало могут случаться null
Re[11]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Во-первых, я специально написал “при свободном владении этими приемами”. Это подразумевает понимание границ применимости этой техники.
Я как раз об этом и говорю. У этой техники весьма узкие границы применимости.
AP>Во-вторых, о каком сравнении пользы и вреда может идти речь, если ты еще даже не знаешь альтернативного варианта
? Сравнение пользы и вреда какого-либо подхода производят, когда есть некоторый известный эталонный вариант реализации; именно от этого эталонного варианта отсчитывают пользу и вред. Т.е. ты оперируешь величинами, не имея точки отсчета для этих величин. В общем, эти твои рассуждения -- чушь.
Чушь — твои рассуждения про чушь. Как минимум у меня есть опыт использования других техник и элементарное сравнение их с ПМ на лямбдах не в пользу последнего.
IT>>... Как правило пока речь идёт о компактных задачах, всё нормально. В алгоритмах на несколько тысяч строк вреда становится существенно больше, чем пользы. AP>Техника является низкоуровневым приемом кодирования, поэтому соотношение между ее достоинствами и недостатками видно уже на небольших кусках кода. Очень сомнительно, что соотношение между достоинствами и недостатками меняется при росте количества строк (я такого не наблюдал).
Ну вот тебе одно неудобство. Поставь точку останова на фукнции, принимающей лямбду. Поставил? А теперь сделай эту лямбду строк на 50. Какого цвета у тебя стал фон в редакторе?
С лямбдами большого размера в C# работать не удобно. Среда для этого не предназначена. ПМ на лямбдах подразумевает интенсивное использование лямбд в одном вызове. Чем они больше, тем менее удобно с ними работать. В Немерле, например, для ПМ сделана специальная поддержка в студии, позволяющая схлопывать паттерны в регионы, реализация которых занимает более одной строки. В результате работа с любым объёмом кода никаких неудобств не вызывает.
IT>>Замена давно придума, качетсвенная и на порядки более мощная — ПМ. Непонятно, почему Хейльсберг и ко так сильно ей противится. AP>Эээ, что-то ты спрыгиваешь с контекста разговора. Ты пишешь, что сделал бранч для рефакторинга, я спрашиваю, на что заменять будешь. В моем последнем предложении слово “замена” именно в контексте твоего рефакторинга. Причем тут замена в виде ПМ? Нет у тебя замены в рамках C# 4.0, так и напиши, зачем юлить?
Так я ещё не решил. Может я всю эту кухню на Немерле перепишу.
IT>>А эмуляция МП на лямбдах — да, извини, но это самое обыкновенное унылое овно. Поначалу немного вставляет, но быстро проходит. AP>Я не сомневаюсь, что ПМ замечательная вещь, и что с его помощью тоже можно решить рассматриваемую задачу. Но суть в том, что для рассматриваемой задачи решения через ПМ и без него являются одинаковыми, совпадение решений почти посимвольное
Ключевое слово здесь — "почти". Не понятно вообще зачем нужен ПМ, если есть такая классная вещь как лямбда
Как минимум для отладки этого кода нужно будет либо занырнуть в твой метод и вынурнуть в одной из лямбд, либо перенести тело лямбды на новую строку, чтобы суметь поставить в её теле точку остановки.
AP>Как насчет ковариантности по generic параметру при реализации через ПМ? Потребуется ковариантность классов, а этого сейчас опять таки нет в языке.
В каком языке?
AP>В общем, у нас уже есть решение, которое, во-первых, не требует расширений языка, а, во-вторых, ни в чем не уступает варианту через ПМ. Поэтому рассмотрение ПМ в рамках данного треда становится неуместным.
Почему не уместным? Ты же как раз именно его изобрёл
Если нам не помогут, то мы тоже никого не пощадим.
Re[12]: Optional Value. Уменьшение количества null reference
Здравствуйте, IT, Вы писали:
AP>>Во-первых, я специально написал “при свободном владении этими приемами”. Это подразумевает понимание границ применимости этой техники. IT>Я как раз об этом и говорю. У этой техники весьма узкие границы применимости.
А я не об этом! Границы применимости весьма широкие.
AP>>Во-вторых, о каком сравнении пользы и вреда может идти речь, если ты еще даже не знаешь альтернативного варианта
? Сравнение пользы и вреда какого-либо подхода производят, когда есть некоторый известный эталонный вариант реализации; именно от этого эталонного варианта отсчитывают пользу и вред. Т.е. ты оперируешь величинами, не имея точки отсчета для этих величин. В общем, эти твои рассуждения -- чушь. IT>Чушь — твои рассуждения про чушь. Как минимум у меня есть опыт использования других техник и элементарное сравнение их с ПМ на лямбдах не в пользу последнего.
Ну какие, какие техники? Скажи же уже наконец, не томи . А пока ты не назвал эталонную технику, с которой сравниваешь, мое доказательство того, что твои рассуждения чушь, остается в силе.
IT>Ну вот тебе одно неудобство. Поставь точку останова на фукнции, принимающей лямбду. Поставил? А теперь сделай эту лямбду строк на 50. Какого цвета у тебя стал фон в редакторе?
Не пойму в чем проблема, в цвете? Цвета в VS настраиваются.
Всё ожидаемо и логично, цветом выделяется выражение, на котором стоит брекпоинт, каких-либо неудобств у меня это не вызывает, я к цветам неприхотлив.
IT>Ключевое слово здесь — "почти". Не понятно вообще зачем нужен ПМ, если есть такая классная вещь как лямбда IT>Как минимум для отладки этого кода нужно будет либо занырнуть в твой метод и вынурнуть в одной из лямбд, либо перенести тело лямбды на новую строку, чтобы суметь поставить в её теле точку остановки.
Требуются пояснение, почему “ключевое слово здесь — "почти"”? Пока это голословно.
Брекпоинты можно ставить с точностью до символа (F9).
А вообще, аргумент абсурден до безобразия, давайте зафигачим все функции в язык, поскольку если их вынести в библиотеки, то в них дебагер заходит, неудобно.
IT>С лямбдами большого размера в C# работать не удобно. Среда для этого не предназначена. ПМ на лямбдах подразумевает интенсивное использование лямбд в одном вызове. Чем они больше, тем менее удобно с ними работать. В Немерле, например, для ПМ сделана специальная поддержка в студии, позволяющая схлопывать паттерны в регионы, реализация которых занимает более одной строки. В результате работа с любым объёмом кода никаких неудобств не вызывает.
А в IDEA, например, любые блоки можно сворачивать: if, for и т.д. Т.е. проблема более общего плана, а не специфична для лямбд. Просто надо сделать также как в IDEA и будет нам счастье . И делать специальную поддержку ПМ со стороны среды не нужно. А на текущий момент меня удовлетворяет resharper-овская рамка, охватывающая регион между скобками.
IT>Так я ещё не решил. Может я всю эту кухню на Немерле перепишу.
Так и пиши, что отказ от “говеной” техники влечет за собой отказ от C#-а. Всё стало бы гораздо прозрачней.
IT>В каком языке?
В C#, тред то про него .
AP>>В общем, у нас уже есть решение, которое, во-первых, не требует расширений языка, а, во-вторых, ни в чем не уступает варианту через ПМ. Поэтому рассмотрение ПМ в рамках данного треда становится неуместным. IT>Почему не уместным? Ты же как раз именно его изобрёл
Да не изобретал я ПМ. Не формулировал я задачу, как покрыть лямбдами юзкейсы ПМ-а. Я решал другую конкретную задачу. Сделав пару элементарных привычных шагов по выносу общей функциональности в отдельный модуль, я получил решение конкретной задачи на языке C#. Получилось некоторое сходство с ПМ-ом, но что с этим сходством делать?
Далее твоя логика: о так это ж мы ПМ получили, блин, но не совсем ПМ, ооо... тогда в топку, поскольку ПМ это ууууууу, ПМ это ааааааааа! И выкидываем сначала решение исходной задачи, а потом уж и сам язык C# полетел в топку.
Кстати, ПМ ты мыслишь вместе discriminated union? или ты хочешь в C# ввести ПМ без discriminated union?
IT>... ПМ на лямбдах подразумевает интенсивное использование лямбд в одном вызове...
Кстати, если лямбд передается много в один метод, то я иногда множество лямбд заменяю на интерфейс и классы с ручным прописывание замыканий. Да, слегка громоздко, но при навигационной поддержке ReSharper-а эта громоздкость не сильно чувствуется.
Re[13]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
IT>>Я как раз об этом и говорю. У этой техники весьма узкие границы применимости. AP>А я не об этом! Границы применимости весьма широкие.
У песочной лопатки тоже границы применимости широкие. Но котлованы почему-то удобнее рыть экскаваторами.
IT>>Чушь — твои рассуждения про чушь. Как минимум у меня есть опыт использования других техник и элементарное сравнение их с ПМ на лямбдах не в пользу последнего. AP>Ну какие, какие техники? Скажи же уже наконец, не томи . А пока ты не назвал эталонную технику, с которой сравниваешь, мое доказательство того, что твои рассуждения чушь, остается в силе.
Мне нравится твоя примитивная логика. Назвать техники? Например, тот же ООП. Назвал? Теперь твои рассуждения — чушь.
IT>>Ну вот тебе одно неудобство. Поставь точку останова на фукнции, принимающей лямбду. Поставил? А теперь сделай эту лямбду строк на 50. Какого цвета у тебя стал фон в редакторе? AP>Не пойму в чем проблема, в цвете? Цвета в VS настраиваются. AP>Всё ожидаемо и логично, цветом выделяется выражение, на котором стоит брекпоинт, каких-либо неудобств у меня это не вызывает, я к цветам неприхотлив.
Молодца. А к одному единственному брейкпоинту размером в экран ты прихотлив?
IT>>Ключевое слово здесь — "почти". Не понятно вообще зачем нужен ПМ, если есть такая классная вещь как лямбда IT>>Как минимум для отладки этого кода нужно будет либо занырнуть в твой метод и вынурнуть в одной из лямбд, либо перенести тело лямбды на новую строку, чтобы суметь поставить в её теле точку остановки. AP>Требуются пояснение, почему “ключевое слово здесь — "почти"”? Пока это голословно.
А разве это не ясно из твоего кода? Или ты не только к цвету, но и вообще к любому мусору неприхотлив?
AP>Брекпоинты можно ставить с точностью до символа (F9).
Ага, в режиме отладки. Только чтобы поставить брейкпоин (F9) в режиме отладки нужно сначала где-то остановиться.
AP>А вообще, аргумент абсурден до безобразия, давайте зафигачим все функции в язык, поскольку если их вынести в библиотеки, то в них дебагер заходит, неудобно.
Точно! Мне твоя изощрённая (или извращённая, пока не знаю как правильней) логика нравится всё больше.
AP>А в IDEA, например, любые блоки можно сворачивать: if, for и т.д. Т.е. проблема более общего плана, а не специфична для лямбд. Просто надо сделать также как в IDEA и будет нам счастье . И делать специальную поддержку ПМ со стороны среды не нужно.
Этого решили не делать из соображений целесообразности.
AP>А на текущий момент меня удовлетворяет resharper-овская рамка, охватывающая регион между скобками.
В глазах от рамок не рябит?
IT>>Так я ещё не решил. Может я всю эту кухню на Немерле перепишу. AP>Так и пиши, что отказ от “говеной” техники влечет за собой отказ от C#-а. Всё стало бы гораздо прозрачней.
Да я как бы этого никогда и не скрывал C# не самый лучший язык для решения определённого класса задач.
AP>Да не изобретал я ПМ. Не формулировал я задачу, как покрыть лямбдами юзкейсы ПМ-а. Я решал другую конкретную задачу. Сделав пару элементарных привычных шагов по выносу общей функциональности в отдельный модуль, я получил решение конкретной задачи на языке C#. Получилось некоторое сходство с ПМ-ом, но что с этим сходством делать? AP>Далее твоя логика: о так это ж мы ПМ получили, блин, но не совсем ПМ, ооо... тогда в топку, поскольку ПМ это ууууууу, ПМ это ааааааааа! И выкидываем сначала решение исходной задачи, а потом уж и сам язык C# полетел в топку.
Была бы моя воля полетел бы. Но пока нельзя. А по поводу твоего решения — не парься. Нормальный велосипед. Не думаю, что он далёко ушел по удобству использования от тех же '?:', '??', но кому-то может и понравится поначалу. С другой стороны народу полезно знать, какие ещё бывают альтернативы, в том числе встроенные в другие языки.
AP>Кстати, ПМ ты мыслишь вместе discriminated union? или ты хочешь в C# ввести ПМ без discriminated union?
Both.
IT>>... ПМ на лямбдах подразумевает интенсивное использование лямбд в одном вызове... AP>Кстати, если лямбд передается много в один метод, то я иногда множество лямбд заменяю на интерфейс и классы с ручным прописывание замыканий. Да, слегка громоздко, но при навигационной поддержке ReSharper-а эта громоздкость не сильно чувствуется.
Приходится отказываться от замыканий и размазывать логику по разным местам. Хотя, при усложнении логики, конечно же, приходится выносить её в отдельные модули.
Если нам не помогут, то мы тоже никого не пощадим.
Re[14]: Optional Value. Уменьшение количества null reference
Здравствуйте, IT, Вы писали:
AP>>Брекпоинты можно ставить с точностью до символа (F9). IT>Ага, в режиме отладки. Только чтобы поставить брейкпоин (F9) в режиме отладки нужно сначала где-то остановиться.
Нет! Брекпоинты с точностью до символа ставятся в любом режиме. Это делается с помощью F9 или с помощью контекстного меню Breakpoint->Insert Breakpoint.