Как стать автором
Обновить
60
0
Viktor @wentout

системный анализ

Отправить сообщение
Не уверен, что это настолько критично, но вам видней.

И всё же, если посмотреть немножко на то, что они уже сделали — «Блог компании Quarkly», — то можно увидеть, что ребята нормально так Open Source'ят: "Как мы отказались от использования Styled-System для создания компонентов и изобрели собственный велосипед". Да и в статье есть отсылки, что много ещё чего в перспективе будет доступно в исходниках же )

Конечно, все мы знаем, что сам по себе NPM — та ещё свалка.

Но! Это же не мешает делать нормально )

А так избранная концепция критики, что, мол "@quarkly/components", "@quarkly/widgets" — это не комильфо, не содержит обоснований того, что конкретно не так…

То есть, иначе говоря: в чём ваша критика конструктивна? Просто негатив от того, что кто-то создал ещё один набор компонент для своих задач? Так может быть если бы другие наборы решали бы эти самые поставленные задачи, то не было бы необходимости делать ещё один? )
Блин, столько инструментов для вёрстки лендингов из блоков, а смотрим — только наборы слов от громких критиков в комментариях…
Хабр, я поступил неправильно, создав критику этой статье. Я об этом сожалею. Знай это.
Хорошая статья, спасибо )

Как будто бы значение результатов вызова Object.prototype.toString.call в некоторой части подозрительно совпадает с кодом ниже:

[].constructor.name // Array для [object Array]
{}.constructor.name // Object для [object Object]
(()=>{}).constructor.name // Function для [object Function]

, подозреваю, что в этом есть какой-то такой явный намёк…
Спасибо, Да, ввёл в заблуждение )
Но side эффекты так себе :)

const MyConstructor = function () {};
const myInstance = new MyConstructor();
// next line: readonly works
myInstance.constructor.name = 'zzz';

// next 2 lines: MyConstructor
console.log(myInstance.constructor.name);
console.log(MyConstructor.name);
Object.defineProperty(myInstance.constructor, 'name', {
	get () {
		return 'всё прекрасно меняется';
	}
});

// next 2 lines: всё прекрасно меняется
console.log(myInstance.constructor.name);
console.log(MyConstructor.name);

Так, эмм, теперь уже я не понял видимо:

1. Проверка на instanceof — это НЕ сравнение с конструктором, это сравнение с прототипом, то, что свойство .prototype вернёт: раздел "`instanceof` lies" тут. И ещё при этом если нужна проверка, то должна же быть ссылка на конструктор где-то рядом же )

2. Имя конструктора невозможно изменить, это readonly свойство. Т.о. анонимные функции и классы лучше не использовать.

3. Для того, чтобы использовать не только лишь имя, можно использовать дополнительно проверку по Symbol.hasInstance. Придётся немного повозиться, но в целом — почему нет )

То, что new Map() instanceof Object //=> true — это, надеюсь, понятно теперь, что это просто проверка не совсем правильная? Т.е., так можно проверить, что это нечто имеет в своём составе прототип от Object. Но это не то, что мы бы хотели получить, верно же?

Эмм… раз вопрос мне, то, видимо ничего страшного не будет, если я дам ссылку на немного дополнительных странных мыслей по этому поводу тут.
Через instanceof проверять имеет смысл только то, что имеет объектную природу, т.е. наследуется от типа Object. Но, instanceof не всегда показывает то, что хочется, он всего лишь проверяет ссылку на прототип. Т.е., мне подумалось, что зная .constructor.name мы могли бы как бы делать дополнительную проверку, т.к. это свойство устанавливается по имени конструктора, если оно задано. Т.е., если запретить анонимные классы и анонимные функции использовать в качестве конструкторов, то можно с этим поиграться. Но это «такое», да… Да и зачем, если оно уже встроено же в TypeScript на этапе компиляции, как вы верно заметили )

Про Proxy и каррирование: тут всё ещё хуже. Насколько я понял, основная суть вопроса была через Object получить такое же поведение, как есть у Map. В этом случае придётся повозиться, но всё равно ничего толкового не получится )

Каррирование используется для методов же. Т.е., если есть метод то его легко каррировать. И, т.о., наследуя от Map мы можем сделать override для .has, а, значит, мы получили дополнительную степень свободы. В случае с Object это сделать тоже можно, но, если свойства нет, то поиск устремится в прототип и в итоге дойдёт до самого конца, т.е. до null. В этом случае сделать аналогию с .has будет сложней, т.к. если мы хотели бы иметь возможность проверять наличие в структуре коллекции вещей, которые являются не строковыми ключами, то в конец цепочки прототипов придётся поставить Proxy, а сами эти вещи хранить как-нибудь отдельно, иначе же они так и окажутся строковыми ключами. Например какую-нибудь такую лютую дичь:

const myObj = {};

const nonStringKey = function () {};

const myObjNonStringKeys = [nonStringKey];
const myObjNonStringValues = ['nonStringValue'];

const proxyForObjectNonStringKey = new Proxy(myObjNonStringKeys, {
	get (target, nonStringKeyAsString) {
		// accessor nonStringKeyAsString может быть только строкой
		// поэтому придётся проверять ключи, как строки
		// можно попытаться что-нибудь придумать с хешированием
		// но это отдельная, ещё более жуткая история
		// ничего кроме строк же...
		
		let valueToReturn;
		myObjNonStringKeys.filter((key, index) => {
			if (
				key.toString istanceof Function &&
				key.toString() === nonStringKeyAsString
			) {
				// примерно здесь каррирование реализуем
				// но для примера просто вернём значение
				valueToReturn = myObjNonStringValues[index];
			}
		});
		return valueToReturn;
	}
});

Object.setPrototypeOf(myObj, proxyForObjectNonStringKey);

const s = myObj[nonStringKey];

console.log(s); // 'nonStringValue'



То есть даже с Proxy безошибочной ситуации не получится… И к этому коду придётся добавить ещё тонну всего, чтобы конвертация строкового ключа «на входе» могла хоть как-то работать. Но всё равно ничего нормального не выйдет, т.к. тут уже overhead такой, и качество кода такое, что ни один вменяемый code-reivew не пройдёт ни при каких условиях, даже если очень надо )
Код субъективно красивей, и в некотором смысле «типизировать» проще )

if (myMapInstance.has(something)) ...


Читается гораздо луче чем:
if (myObjectAsCollection[something]) ...


И ещё, т.к. в случе с `Map` для проверки нужно вызвать метод, то добавляется дополнительная степень свободы, ведь раз `.has()` является методом, то его можно напрямую каррировать, а не изобретать велосипеды с Proxy )

С «типизацией» же всё становится немного ещё интересней, вот:

(new Map()).constructor.name === 'Map';


В то время как:
({}).constructor.name === 'Object';


И вот когда если это смешиваешь с наследованием через `extends`, то получается Номинальная Типизация «искаропки» )

А если хочется в бенчмаркинг, то опять же, нужно же понимать, что поиск в Hash-таблице по строковому ключу радикально отличается от поиска по произвольному типу ключа с вызовом метода. Т.е., использовать какую-нибудь объектную сущность в качестве ключа у объектов и их производных `{}` просто тупо нельзя же, а в случае с Map — да пожалуйста, делай что хочешь. )
Прикольная статья )

Только вот про фронтендеров немного не всё правда. Уже давно есть другие виды коллекций: Map, Set. Есть их оптимизации для GC: WeakMap, WeakSet. К тому же есть proposal в спеку про Record и Tuple. Т.е., однозначно прям так говорить лучше лишь про старые версии. Ведь JS один из самых динамично развивающихся ЯП в последнее время )

К тому же причислять Object к коллекциям тоже не совсем верно. Скорее это вынужденное использование встроенной возможности создать пары «ключ»~«значение», где ключом будет строка и с недавнего времени Symbol, да и Array — это же тоже по сути Object, просто с другими ключами. Т.е. на мой субъективный взгляд правильней было бы написать «где до недавнего времени не было ни одной настоящей» коллекции )
Спасибо за статью )

Ребят, поясните про эффекты?
> Основным отличием Atomize от Styled-System являются «effects».

Как вы относитесь к возможным проблемам из-за того, что это в принципе всё же Side Effects?
в пару строк не получится, но есть библиотека

Суть в том, что конструкторы добавляются в прототип. Делегирование через this. При создании экземпляра в прототип докидываются конструкторы следующей итерации. Получается pipleine с деревовидным образцом. Но сами экземпляры получаются через конструирование. Т.е. в цепочке все предыдущие делегаты. Есть instanceof не только для конструкторов, но и для экземпляров. Кроме того есть хуки, а значит тесты и валидация и т.п. При этом аргументы конструкторов можно сохранять, чтобы проверять как был создан экземпляр, например. В любой момент можно отсоединиться через .extract() получив все перечислимые свойства. Так же есть .fork() с новыми аргументами. Есть DAG через .call(). И, к тому же можно унаследоваться от, например, синглтонов вроде ReactDom или jQuery, или window и получить свою кастомную «надстройку». И т.п., в общем, можно играться. Ключевое: эта библиотека — это прототип, идеология. Лицензия MIT, и можно по образцу склепать своё, если очень интересно, или взять как есть и не мучаться )

image

Из проблем: overhead, т.к. используются фабрики конструкторов, т.к. иначе не сделать, ветвление, т.к. прототип будет «расшарен» если не использовать фабрику конструктора для создания экземпляра. Суть именно в том, как устроено наследование в JS, в том, как собирается прототип и в обработке instanceof. Т.е. именно это позволяет так типизировать структуры. Подозреваю, что это можно повторить и в других ЯП. Сейчас видится как такая наивная попытка поиграться в нечто вроде HoTT, возможно попытка, возможно нет, но это явно какой-то другой мир, но тоже JavaScript.

twitter.com/went_out/status/1189187779395108864
c `undefined` абсолютно всё так, правда тут сразу две ещё неясности:
— значение не определено
— значение есть, но оно undefined

Т.е., допустим у объекта есть свойство, но оно undefined, но [[accessor]] определён, и/или же он вообще ещё не был определён. Простыми проверками разница не видна, а если это важно, чтобы она была, придётся сильно помучатся со сбором именно всех свойств именно текущего уровня объекта ): Object.keys или Object.getOwnPropertyNames и ещё вдруг там что-нибудь новенькое, например Object.getOwnPropertySymbols…

С `null` для примитивов явное указание, что в значении ничего нет. Но само значение есть, т.е., опять же он вроде бы как нужен и для примитивов тоже. Но вот увы, с «дальнейшим» развитием идеологии `null` становится уже не таким примитивным, а его объектная природа была указана даже в первой спеке (правда её из Runtime проверить было невозможно), и здесь возникает иная ситуация: т.к. нигде нет явного запрета замещать `null` каким-угодно другим примитивом. Это создаёт путаницу, что, мол, вместо `null` можно класть всё, что угодно. Можно то оно можно, но идеологически в корне неверно, вместо null можно класть объект или любой из конструктивных примитивов: new Date, new String, new Boolean и т.п.

Замещать null обычными примитивами — выстрел в ногу, т.к. это и есть те ошибки, которые потом ничем и никак не отслеживаются, т.к. конструктор не вызывался.
Побуду К.О.: Название слишком Click Bait, вот все и побежали. Ожидания у всех были разные, хейтеры ломанулись хейтить, защитники решили позащищать, многие просто запаслись попкорном и не только лишь некоторые не смогли его доесть.
Спасибо за такой отличный комментарий, здорово было бы бы прочесть его в виде обзорной статьи )
Единственное, что хочется дополнить, что `typeof null` — совсем неправильно называть «ошибкой», скорей — это система взаимосвязанных случайностей. Подозрительно подходящих друг другу систематически воспроизведённых мнимых случайностей. И все они созданы или по доброй воле или в угоду правилу «не ломайте web».

И даже больше, это критически важная особенность, и она по своей значимости гораздо интересней, чем всем известная ошибка на миллион. И, что может быть даже ещё важней — это могла быть попытка исправить первоначальную проблему с `null`. Не все понимали, что он нужен для объектов, а его использование в качестве данных, хоть и имеет определённый смысл, но в целом скорее излишнее обобщение.

В недавнем общении с Бренданом Айком мы прямым ответом выяснили, что `Object.prototype` создан именно таким, в угоду тому, что необходимую идеологию даёт лишь сравнение с приведением типа, т.е. фраза `Use == null`. Но, конечно, он и раньше высказывался подобным образом на этот вопрос. Понять смысл этого можно только лишь попытавшись представить картину взаимосвязей в системе прототипного наследования JavaScript в целом, а так же то, какие проблемы оно решает. Здесь нет типичных нам задач, суть в pipline жизненного цикла взаимосвязанных объектов. И это поведение может очень пригодится, если захотеть наследоваться от стартовой точки. Т.е., если есть некий Main, который null, а всё остальное поведение есть его наследники в Trie, например Execution Path или Data Flow. В этом случае система прототипного наследования в JS в целом решает Expression Problem через делегирование посредством «наследных» конструкторов. Важно, что в .prototype конструктора должен лежать «предшествующий» экземпляр. Если смотреть на систему таким образом, то всё становится очевидно и совершенно прозрачно. Просто 25 лет прошло, и это всё «затерялось», многие даже не знают, что так можно.

image

github.com/tc39/ecma262/pull/1913#issuecomment-603580098
`instanceof` про интерфейсы — это… )
Он бы мог работать как нужно, если бы интерфейс был экземпляром конструктора этого интерфейса. Но, боюсь, что если создать в народе понимание, что делать интерфейсы экземплярами классов в принципе можно, ещё возможно, то вот убедить их в необходимости будет гораздо сложней.
Да! И именно!
Корни JavaScript были заложены ещё раньше. Даже не в прямых предшественниках вроде Simula. Работы по проектированию вокрыг подобных ЯП велись намного раньше, просто было взято то, что быстро подходило под проект.
Версия событий от автора языка и редактора стандарта:
zenodo.org/record/3710954#.Xq6zO3Vfhzm
Не знаю, мне всё равно, лишь бы автор прочёл.
Но, всё же, может быть потому, что не верят :)
Хотя, что правда, то правда, на LLVM ничего не собирал, и на С~C++ не пишу.
Да, конечно, тут перегнул с сожалениями :)
Цепляет, в том то и дело, что цепляет настолько, что хочется посмотреть описание и структуру, а приходится сразу лезть в исходники. Может быть, конечно, это такой хитрый план, тогда автору ещё большее уважение, т.к. время как будто бы не тратил, а социальную инженерию тоже как-то почувствовал, несмотря на такую вот «всю эту» историю. Поправил. Спасибо :)
Taetricus
Саша, мне понравилась история мучений с языком, спасибо, было прикольно, хоть кино снимай. Напугало, что «история» появилась раньше описания языка. Искренне считал, что уже лет 10 так никто не делает, потому, что вроде бы как теперь читать истории — дорого.

Поэтому решил всё же посмотреть исходники, где, как и предполагал, убедился, что идиосинкразии они не вызывают: значит уже хорошо!

Вопрос: можешь ли ты переписать свой Transpiler так, чтобы его можно было исполнять в VM в JavaScript (Node.js или Браузер — не суть), или же, что может быть намного лучше — для TypeScript?

Видишь ли, Deno уже на подходе, а значит VM на Rust очень скоро поедет у кого-нибудь в Prod…
С~C++ — это сложная и многоликая аудитория, они могут всё, и даже больше чем хотят. Пока ты учил компиляторы, многие остальные люди учили «популярность», «маркетинг» и прочие странные нам, инженерам, вещи.

В мире много языков программирования, и ещё один язык общего назначения нужен мало кому. В мире JavaScript народ попроще будет, да и народа намного больше. Банальнальная статистика подсказывает, что вероятность, что кому-нибудь понравится твоё видение прекрасного, увы, намного выше, чем то, как оно может быть использовано сейчас. Заодно профессию получишь, востребованную, сразу, сходу. Не знаю, стал ли бы я на твоём месте «играться», в эту подмену «чистого искусства» на бытовые радости, и стоит ли эта игра свеч в принципе, но почему бы не попробовать? Умение добиваться поставленных целей, ответственность и собственный взгляд на искусство программирования могли бы быть приятным дополнением к, например, такой строке в резюме: «написал свой транспайлер в TypeScript т.к. мне хотелось писать на мной созданном языке» — это сразу покажет людям уровень твоей квалификации. И хоть скорее всего это не будет не так сложно и возвышенно, как создание собственного компилятора, но, по крайней мере людям будет понятно с кем они имеют дело, и почему он уверен, что заслуживает внимания и прочее, тому подобное, коммуникабельное и измеримое.
1
23 ...

Информация

В рейтинге
Не участвует
Откуда
Россия
Дата рождения
Зарегистрирован
Активность