Pull to refresh

Comments 24

За статью плюс, но про null и undefined супротив zero value принципиально не согласен. Это очень грамотная фишка js

Это просто следствие использования вариантного типа. Иначе бы не вышло.
null - это zero value для object, а undefined - zero value для variant.

Поддержу. Go не знаю, и мне вот вообще не понятно, как объявить к примеру юзера, возраст которого опционален - то есть, по заветам JS, number или undefined. Go в данном случае всё равно установит возраст 0 по умолчанию? Как тогда отличить пользователя, который возраст никогда не указывал, от того, возраст которого действительно(и внезапно) 0?

Плохая идея

Это заставляет писать проверку if =!nil каждый раз при работе с объемом

Но это то, что нужно. Если пользователь не указал возраст, то его возраст неизвестен. И нужно всегда проверять, известен ли нам возраст пользователя

Тишка ниже написал более серьезную проблему

Проверка на nil ещё ладно. Тут проблема, в другом - теперь мы не отличаем указать на возраст и опциональный возраст. И как следствие - не можем сделать not nil указатель.

Да, сам с этим сталкивался, достаточно больно

Всегда инициализировать это поле со значением -1?

Предложу как один из вариантов создать свой тип Age с методом Value() (uint, bool). Если Value вернет true, значит, значение в типе верное (инициализированное). При возврате false будет означать undefined.

Просто в struct указать что поле age будет *int (ссылкой на место в памяти где может будет int), а такой тип может быть nil

У вас сломанный пример, возраст не может быть 0, setter не должен позволять делать такого, и как указали ниже можно делать как в Сях -1, во взрослых языках value типы могут иметь nullable значения, если уж сильно хочется.

Чему равен возраст месячного ребёнка, если считать в целых числах?

Это актуальная проблема. Как вы смотрите на создание ValueObject?

type UserAge struct {
  age int
  filled bool
}

Не удобно писать код с телефона, но, надеюсь, мысль передал. Поля приватные, экземпляр создается через конструктор. Там же может быть валидация. Публичный геттер может возвращать два значения для проверки и обработки. Zerovalue структуры будет иметь filled false, что так же корректно обрабатывается

Как вы смотрите на создание ValueObject?

Как на создание объекта там, где в JS справился бы примитив)

Справедливости ради в TS/JS наследование это всего лишь удобство синтаксиса.

На деле мы можем как и раньше менять прототипы и использовать defineObject.

Также и с методами их можно отдельно писать как и делали раньше.

Просто это достало ;)

Именно так. class в JS сахар над прототипами, появившийся в ES6 чтобы не писать Object.create() и Object.defineProperty() руками.

Go в этом смысле честнее: нет притворяющегося классом синтаксиса. Структура это данные. Методы отдельно. Композиция через встраивание явная. Никто не ожидает поведения "настоящего" ООП и не удивляется, когда его нет.

В JS классы создали иллюзию привычного ООП для людей из Java/C#. Иллюзия работает, пока не полезешь в _proto_ или не попробуешь сделать множественное наследование. Тогда вспоминаешь, что под капотом всё те же прототипы.

Отказ от undefined не спасет от криворуких кодеров. Ну не тут, так в другом месте напишут такое, что будет падать. И сделают они это со свойственной им тупизной. ТС, конечно, накидывает на вентилятор - кто сейчас в js проверяет опциональные свойства когда для этого есть специальный оператор?

100%... Падает со страшным грохотом так же легко как в js

Про криворуких кодеров согласен, от них не спасёт никакой язык. Можно и на Rust написать что-то, что будет падать, если очень постараться. Но речь не о защите от злого умысла, речь о том, какой код получается по умолчанию.

Про ?. (optional chaining) справедливое замечание. Действительно, с ES2020 ситуация стала лучше:

const name = user?.profile?.name ?? "Anonymous";

Но тут два нюанса:

?. это костыль поверх проблемы, а не её решение. Вы всё равно должны помнить, где нужен ?., а где нет. В Go нулевое значение это дефолт, а не исключение. Разница в когнитивной нагрузке.
?. появился в 2020. Sentry-ошибки из статьи это реальный опыт 2017-2019 годов. Легаси-код без optional chaining живёт и здравствует.

Но вы правы, в современном JS эта проблема смягчена. Можно было упомянуть ?. как контрпример. Статья фокусируется на различиях в философии языков, а не на современных workaround'ах, но замечание учту, спасибо.

Вы всё равно должны помнить, где нужен ?., а где нет

Вам это подскажет TS прямо в IDE. В вашем примере если name является обязательным аргументом там, куда передаётся, без ?. у name ТС начнёт ругаться на то, что константа может быть undefined

Все .go файлы в одной директории должны объявлять один и тот же package. Они видят друг друга полностью, как если бы были одним файлом.

В такой форме это путает новичка. Если все файлы должны иметь одну и ту же строку, то зачем она вообще нужна? Ну, может быть если файлы вдруг перескочат из одного каталога в другой...

Если бы написать чуть полнее, скажем про go.work, go.mod и то, когда имена пакета и директории могут не совпадать - будет понятно, что обязательный package не 100% исторически сложившееся уродство, а в нём есть и некоторая логика и некий потенциал на мало ли что в будущем. Мне кажется, что в статье изложено меньше чем квант.

Про "видят друг друга полностью" - неверно. Файлы друг друга не видят вообще, их видит команда go. Поэтому в одном каталоге может быть несколько .go файлов в каждом из которых есть и "package main" и "func main" и команды типа "go run m_v3.go p1.go p2.go" и "go run m_v1.go p1.go p2.go" будут работать, а комманда "go run ." - нет.

Такие мелочи важны как раз для начинающих, у них и main может быть в разных вариантах, и раскладка по модулям плавать.

Объявляет и инициализирует переменную одновременно

Тут я бы непременно вставил слово "новую", как минимум. Иначе это тоже запутывает новичка. А про "новую" он, даже читая по верхам, точно вспомнит как только слева от := окажется больше одной переменной.

В JavaScript два пустых значения: undefined и null. Тони Хоар назвал null "ошибкой на миллиард долларов". JS решил эту проблему... удвоив её.

Он не удвоил, он именно решил... для случая когда возможны ровно три состояния - известно, неизвестно, не спрашивали. Так нередко и бывает, поэтому в комментариях некоторые и пишут что получилось хорошо. Как только состояний больше - JS требует задуматься, а весь огород вокруг undefined и nil только мешает. В Go такого нет, да.

То же самое относится и к обработке ошибок. Пока состояний два - получилось и упс, try да ? работают идеально. Как только задача не столь тривиальна - метод Go удобнее чем баян который можно нагородить вокруг типов исключений и отметки мест откуда они.

Спасибо за развёрнутый разбор.

Про package и организацию модулей. Да, я сознательно упростил. Статья для JS-разработчиков, которые только смотрят в сторону Go. Полноценное объяснение go.mod, go.work, рабочих пространств и случаев несовпадения имени пакета и директории это отдельная статья. Здесь ментальная модель "пакет = папка" работает в 95% случаев для входа в язык.

Но согласен, что фраза "видят друг друга полностью" технически неаккуратна. Файлы видит go, а не друг друга. И ваш пример с go run m_v3.go p1.go p2.go vs go run . отличная иллюстрация того, как упрощение может сбить с толку. Исправлю формулировку.

Про := и "новую" согласен на 100%. Там действительно нужно слово "новую", иначе при x, err := …; y, err := … начинающий запутается. Спасибо, поправлю.

Про undefined/null и "удвоение проблемы". Тут я остаюсь при своём. Три состояния "известно / неизвестно / не спрашивали" это нюанс, который появляется в конкретных доменных задачах. Для 80% кода это просто два способа получить TypeError. Про "решил" - вопрос вкуса. Моё мнение: если типичный вопрос на собеседовании "в чём разница между null и undefined" это признак неудачного дизайна, а не решения проблемы.

Про обработку ошибок согласен частично. Для сложных сценариев Go-подход действительно удобнее благодаря явности. Но try/catch тоже не просто так существуют 30+ лет. Оба подхода имеют своё место. Статья намеренно показывает Go в положительном свете. Это материал для тех, кто рассматривает переход.

Sign up to leave a comment.

Articles