Как стать автором
Обновить

Комментарии 22

Хорошая статья, но как-то слишком много текста что-ли.

И хорошо добавить гифку с игрой, чтобы без перехода было важно, о чем речь

Полностью согласен. Гифки с игрой не хватает, было бы легче визуализировать все модели и логику. Было бы неплохо прогнать статью на опечатки, например "Минималное"

Введите слово class, выберите "MAM class definition" и нажмите TAB или ENTER

Если я хоть один раз запускал IDE, я знаю как печатать

Чтобы отформатировать код также как у меня, нажмите CTRL+SHIFT+P, введите "Format" и выберите команду "Format document" :)

У меня Mac+WebStorm и ctrl+shift+p у меня не сработает. У каждого свое окружение, эти описания можно убрать

// Количество пустых трубок
tube_empty_count() { return 2 }

Комментарий просто перевод функции на английский, никакой ценной информации не несет

Блоки кода с пустыми классами только создают больше шума

Тяжело читать, когда столько лишней информации. Настолько подробно описывать действия не стоит. Сосредоточьтесь на коде и осмысленных комментариях.

Лучше просто уточнить в какой среде (хотя вроде понятно что вскод)

$mol навсегда останется маргинальной технологией, код-стайл которого заставляет ужасаться любого JS-разработчика, ранее не имевшего дела с таким способом написания кода. А "@ $mol_action" вообще выглядит как способ заглушать ошибки в PHP: https://www.php.net/manual/en/language.operators.errorcontrol.php

Конечно в случае если разработчики фреймворка не перестанут упрямствовать и не перейдут на общепринятый в экосистеме код стайл.

код стайл это косметика

А у нас своя экосистема из лучших в своём классе библиотек.

А расскажите пожалста зачем такие хитрости вместо return new $hype_ballsort_tube(this.tube_size())

const obj = new $hype_ballsort_tube
obj.size = () => this.tube_size()
return obj

Это что-то вроде инъекции зависимостей? Но зачем такое усложнение? И напрашивается конечно закешировать геттер, чтобы не создавать функцию на каждый шар

Да, я читал это. Ну так и зачем тут это усложнение? Выглядит очень грязным - поди разберись потом, где меняется size у трубы, если приложение большое.
И все-таки, почему не задавать через конструктор? Если прям нужна связь каналов, то
new $hype_ballsort_tube(() => this.tube_size())

В разных местах использования нужно связывать разные каналы. На самом деле можно писать и так:

$hype_ballsort_tube.make({ size: ()=> this.tube_size() })

Но такой код хуже оптимизируется компилятором.

Так а в конструктор то можно или нет? И что мешает?

Там нет кейса про который я говорю

Конкретно в этом случае можно через конструктор передать начальное значение шаров

class $hype_ballsort_tube extends Object {
  constructor(public balls_default: Ball[] = []) {}
  
  @ $mol_mem
  balls(next?: $hype_ballsort_ball[]) {
    return next ?? this.balls_default()
  }
}

А код фабрики стал бы таким:

		@$mol_mem_key
		Tube( index: number ) {
			return new $hype_ballsort_tube(this.tube_size())
		}

Но в целом, в моле конструкторы используются только дли передачи значений по умолчанию, а инстанцируются объекты из свойств-фабрик $mol_mem_key и $mol_mem(если нужен singleton)

Фабрики используются потому что:
- свойства-фабрики ленивые, т.е. объекты создаются непосредственно при обращении к фабрике. Например это помогает для написания интеграционных тестов для приложения, в одном кейсе поднимется только та часть приложения которая непосредственно участвует в кейсе, а остальная часть не поднимется т.к. все ленивое
- свойства-фабрики управляют жизненым циклом подконтрольных объектов, т.е. если они понимают что они больше не нужны, они прибивают подконтрольные объекты и вызывают у них метод destructor в котором можно определить что нужно сделать при уничтожении. В целом это может работать и не течь без наличия garbage collector
- и они устанавливают для подконтрольных объектов глобально-уникальные идентификаторы, которые в том числе используются системой реактивности для отслеживания изменений

А конструкторы используются только для передачи значений по умолчаию из нереактивных источников, потому что если бы tube_size было мемоизированым изменяемым свойством:

@ $mol_mem
tube_size(next?: number) {
  return next ?? 4
}

То тогда вариант с получением его значения и передачей в конструктор был бы не желателен, т.к. если бы кто-то изменил значение в tube_size, это вело бы к устареванию фабрики Tube и повторной актуализацией с пересозданием всех подконтрольных объектов. В некоторых случаях мы бы получили нежелательное поведение.

В таком случае нужно было бы делать как вы написали ниже: `return new $hype_ballsort_tube(() => this.tube_size())`, чтобы небыло вызова tube_size в фабрике.

Но, я воспользовался общим "паттерном" настройки объекта, который описан в ссылках приведенных ниже.

Спасибо за подробное объяснение, это все очень интересно и круто.
Смущает как раз общий паттерн настройки объекта, вижу в нем нарушение целостности и закрытости объекта, что может приводить к проблемам - добавили новый поток, а переопределить его забыли во всех местах создания. Если внешние зависимости создавать в конструкторе, такой опасности нет - тайпскрипт скажет гав.

А зачем его переопределять во всех местах?

при переопределение тайпскрипт проверяет совместимость сигнатур функций

сама концепция предполагает наличие значений по умолчанию, например если тоже самое описывать на языке view.tree - то тут уже нельзя не указать значение по умолчанию

$hyoo_ballsort_game $mol_object
  tube_size 4
  Tube* $hype_ballsort_tube
    size <= tube_size

это равносильно
class $hyoo_ballsort_game extends $mol_object {
  tube_size() { return 4 }
  
  @$mol_mem_key
  Tube( index: number ) {
    const obj = $hype_ballsort_tube
    obj.size = () => this.tube_size()
    return obj
  }
} 

Если не возможно указать значение по умолчанию, то можно сделать так, чтобы разработчик сразу увидел

size() {
  throw new Error('Not implemented')
}

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

Выражение выше не нужно доказывать, я согласен с ним)

Я правильно понял описанный кейс?:

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

В случае с конструктором тс заругается во всех местах использования. А в моем сценарии нужно будет самому искать места и не будет гарантии, что нигде не забыли?

Примерно да, но у инпута могут быть свои особенности, тут скорее речь про модели. В статье есть модель трубы с шариками, и размер этой трубы задается извне. И нужно ей добавить новое поле, например цвет, тоже задаваемое извне. Если это поле добавить в конструктор, то TS будет ругаться, а если использовать способ предложенный в статье, то будет дефолтный цвет, и нужно будет пройти по всем местам создания этой трубы и добавить руками. А если в параллельной ветке появилось новое место, то очень легко это пропустить в прод.

Понял, в случае с молом, применение конструкторов ограничено. Но по факту им является свойство-фабрика. TS-ом тут не проверить, относителная защита только то, что для одного класса не должно быть больше одной фабрики, в идеале

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории