openlang

Приватные кейсы union, smart constructor, а после remove всё равно `Colors []`?

Всем привет,

У меня небольшой редактор образцов цвета с union из трёх кейсов для палитры. Свежая правка — NotEntered, намеренная очистка — Empty, а Colors хранит список. Я сделал кейсы приватными и открыл наружу только ofColors, где ofColors [] даёт Empty. Я рассчитывал, что компилятор сделает невозможным создание Colors [].

В скриптовой сессии (новая палитра, добавить синий, удалить синий, Save) Save выводит "0 colors" вместо "empty (chosen)". Reset работает правильно. Rider не подчёркивает ничего, сборка чистая.

Сначала я заподозрил List.filter, потом то, что Rider использует другой SDK, чем указан в global.json, поэтому пересобрал из терминала. Результат тот же.

Вот функция, которая, как я думаю, за это отвечает:

let remove (name: string) (p: Palette) =
    match p with
    | Colors cs -> Colors(cs |> List.filter (fun c -> c.Name <> name))
    | other -> other

Приватность проверяется только снаружи Palette.fs, и поэтому мой собственный модуль может свободно создавать Colors []? Страница про контроль доступа вроде бы на это намекает, но я не уверен. Если так, то нормальное ли это исправление — пропускать add и remove через ofColors, или неправильно сам тип? Ещё думаю, не будет ли проще обычный список плюс флаг entered.

Спасибо, Oskar

Переведено с английскогоПоказать оригинал

Разговор продолжается 1

Следуя доводам
  1. Ссылка на ответ

    Спасибо за понятное описание, Oskar. Думаю, насчёт приватности вы правы: внутри определяющего модуля конструкторы видны, так что remove может свободно создавать Colors []. В Haskell со скрытыми конструкторами всё работает так же, так что это не особенность F#.

    Прежде чем выбирать фикс, хотелось бы узнать одну вещь. По чему на самом деле матчится Save? Если там есть кейс Colors cs, который печатает количество, он выведет "0 colors" для любого Colors [], независимо от того, как это значение было построено. Проходит ли шаг из свежего состояния в add через ofColors или Colors строится напрямую? Спрашиваю, потому что порядок шагов (add, потом remove, потом Save) определяет, какая функция выдаёт итоговое значение.

    Если вы пропустите remove через ofColors, нужно ли это и для add? Ещё интересно, почему вы отказались от варианта, где Colors хранит непустой список.

    Переведено с английскогоПоказать оригинал

Другие стороны того же вопроса

  1. List<Int> только для чтения - это снимок?

    List<Int> всего лишь представление только для чтения, а не снимок. Он сообщает потребителю, какие операции доступны через эту…

    Ответы 4Последняя активность kotlin
  2. Единицы измерения как дешёвые идентификаторы

    Для целочисленных идентификаторов я пробую единицы измерения вместо объединений с одним случаем, и хочется услышать второе мн…

    Ответы 1Последняя активность fsharp
  3. Валидация JSON перед discriminated union

    Небольшая тулза, которая читает дампы статусов с моих бэкап-хостов и печатает по одной строке на каждый. Каждый файл должен б…

    Ответы 4Последняя активность typescript