Информация об изменениях

Сообщение Return null in TryXyz methods от 24.10.2018 17:20

Изменено 24.10.2018 17:28 Sinix

Return null in TryXyz methods
Камрад @NN__ поднял в реквесте вопрос про возврат null из TryXxx-методов.

Предложение — заменить (все?) такие методы на FW-style bool TryGet(..., out var result). Если неправильно понял или криво сформулировал — пиши, поправлю.

Чтобы не мучать мой английский и привлечь больше участников дублирую тему тут.


Моя точка зрения: я за использование текущего подхода по следующим причинам:

1. Работает. На самом деле это основная и единственная причина.
CJ чисто исторически сложился как сборник штук, которые работают и проверены практикой.

Use cases:
    // async
    var data1 = await cache.TryGetAsync(someKey1); // no way out arg can be here

    // elvis-op & nullable chains:
    var workers1 = consoleArgs.TryGetValue(_workersCountArg)
        ?.ToInt32Invariant()
        ?? 1
    // vs
    var workers2 = consoleArgs.TryGetValue(_workersCountArg, out var result)
        ? result.ToInt32Invariant() ?? 1
        : 1;

    // No way to use together with optional args.
    // By convention the out var result should be the last argument.
    [CanBeNull]
    public LambdaExpression TryGetConvertExpression(
        [NotNull] Type from,
        [NotNull] Type to,
        bool checkNull = true,
        bool createDefault = true)
    {
        Code.NotNull(from, nameof(from));
        Code.NotNull(to,   nameof(to));

        var li = GetConverter(from, to, createDefault);
        return li == null ? null : (LambdaExpression)ReduceDefaultValue(checkNull ? li.CheckNullLambda : li.Lambda);
    }

    // using
    using (var stream = resourceKey.TryGetResourceStream()) // no way out arg can be here
    {
        ...
    }


2. Нет реальных причин для изменений. "Рекомендуется стандартами" — это не причина.
Да, guidelines — это сильный аргумент при выборе из нескольких равноценных решений.
В частности, мы всегда стараемся следовать стандартным паттернам FW для методов, у которых есть аналоги из FW. Словари, методы TryParse и т.д.
При этом мы жертвуем юзабельностью ради минимума WTF moments.
В обсуждаемом случае речь идёт о самостоятельном мини-фреймворке с полностью и здесь вполне можно позволить себе отступление от стандартных рекомендаций.

3. Больше теряем, чем выигрываем.
В CJ есть public api, которое использует var result = TryDoSmth().
Примеры —
var a = Range.TryCreate(from, to);
var b = EnumHelper.TryParse<TEnum>(string name, ignoreCase: false);

Что делаем с ними? Ломаем public API, или оставляем код как есть?
Return null in TryXyz methods
Камрад @NN__ поднял в реквесте вопрос про возврат null из TryXxx-методов.

Предложение — заменить (все?) такие методы на FW-style bool TryGet(..., out var result). Если неправильно понял или криво сформулировал — пиши, поправлю.

Чтобы не мучать мой английский и привлечь больше участников дублирую тему тут.


Моя точка зрения: я за использование текущего подхода по следующим причинам:

1. Работает. На самом деле это основная и единственная причина.
CJ чисто исторически сложился как сборник штук, которые работают и проверены практикой.

Use cases:
    // async
    var data1 = await cache.TryGetAsync(someKey1); // no way out arg can be here

    // elvis-op & nullable chains:
    var workers1 = consoleArgs.TryGetValue(_workersCountArg)
        ?.ToInt32Invariant()
        ?? 1
    // vs
    var workers2 = consoleArgs.TryGetValue(_workersCountArg, out var result)
        ? result.ToInt32Invariant() ?? 1
        : 1;

    // No way to use together with optional args.
    // By convention the out var result should be the last argument.
    [CanBeNull]
    public LambdaExpression TryGetConvertExpression(
        [NotNull] Type from,
        [NotNull] Type to,
        bool checkNull = true,
        bool createDefault = true)
    {
        Code.NotNull(from, nameof(from));
        Code.NotNull(to,   nameof(to));

        var li = GetConverter(from, to, createDefault);
        return li == null ? null : (LambdaExpression)ReduceDefaultValue(checkNull ? li.CheckNullLambda : li.Lambda);
    }

    // using
    using (var stream = resourceKey.TryGetResourceStream()) // no way out arg can be here
    {
        ...
    }


2. Нет реальных причин для изменений. "Рекомендуется стандартами" — это не причина.
Да, guidelines — это сильный аргумент при выборе из нескольких равноценных решений.
В частности, мы всегда стараемся следовать стандартным паттернам FW для методов, у которых есть аналоги из FW. Словари, методы TryParse и т.д.
При этом мы жертвуем юзабельностью ради минимума WTF moments.
В обсуждаемом случае речь идёт о самостоятельном мини-фреймворке и здесь вполне можно позволить себе отступление от стандартных рекомендаций.

3. Больше теряем, чем выигрываем.
В CJ есть public api, которое использует var result = TryDoSmth().
Примеры —
var a = Range.TryCreate(from, to);
var b = EnumHelper.TryParse<TEnum>(string name, ignoreCase: false);

Что делаем с ними? Ломаем public API, или оставляем код как есть?