Что как раз очень правильно в плане обучаемости программистов
И неправильно, как я уже заметил, если мы хотим получить новую вычищенную семантику.
Но в TS в этих случаях транслятор выбрасывает предупреждение
Да ну? Транслятор может статически определить, когда вы выходите за границы массива или случайно передаете
null
в какую-то функцию? Я уж не говорю о том, что вы можете забыть что-то типизировать и тогда у вас там будет Any, про который транслятор ничего не знает.
Почему идентификатор экземпляра фигурирует в интерфейсе класса
В Dart это (как и в CoffeeScript) сокращенная запись для A(x) { this.x = x; } иначе конструкторы будут много boilerplate кода содержать, который будет только и делать, что копировать параметры в поля.
Т.е. он не создан, что бы быть заменой JS?
Зависит от того, как вы понимаете слово «замена».
Он создан для того, чтобы его могли использовать там где сейчас используют JavaScript и при этом иметь определенные удобства, которых JavaScript лишен.
Понятие «дублирует» обычно подразумевает определенную эквивалентность, однако Dart и JavaScript не эквивалентны в семантическом плане. Если бы они были эквивалентны, то Dart бы не был лучше, чем JavaScript.
Извините, не понял. Система классов появляется, о каких типах вы говорите?
Система типов из-за которой TypeScript называется TypeScript, а не просто ES6Script :-) Глава номер 3 в спецификации TypeScript называется Types и начинается словами
TypeScript adds optional static types to JavaScript. Types are used to place static constraints on program entities such as functions, variables, and properties so that compilers and development tools can offer better verification and assistance during software development.
Что вы имеете в виду, можно пример, а то я не понимаю.
Конечно, можно. Например, в Dart есть только одно значение, которое обозначает отсутствие чего-то — null, а в JS их два null и undefined. Если я попробую обратится к полю, которого нет я получу исключение, а не undefined. Если я попробую прочитать за границей массива, я опять же получу исключение, а не undefined. Если я умножу null на 10, я не получу в тихую NaN, а опять же получу исключение.
Иными словами там где JavaScript (и TypeScript) замалчивают ошибки (которые потом приведут к развалу в другом месте), Dart не замалчивает ничего. Ну а дальше семантические различия пошли. В Dart массив это массив, а не непонятно что (потенциально даже дырявое) и т.д.
синтаксис Dart мне кажется в некоторых моментах — анархичным
Мне не совсем понятно, что здесь анархичного. Может вы хотели сказать архаичным? Я бы не сказал, что A(this.x); это совсем уж архаично.
К тому же подход TypeScript для Dart не работает, потому что в Dart у класса может быть несколько конструкторов, поэтому лучше поля объявлять в теле класса, а не в сигнатуре конструктора.
которые друг-друга дублируют
Я бы не сказал, что Dart кого-то дублирует особо, ни как язык, ни как платформа.
вы куда-то не туда смотрите, dart:io (к сожалению, по моему мнению) весь из себя такой-же асинхронный как и браузерный код, и node.js. Причем dart:io использует те же абстракции из библиотеки dart:async, что и браузерный код.
Я не вижу преимуществ в том, чтобы каждая вторая библиотека изобретала свою собственную несовместимую эмуляцию одной и той же парадигмы под названием ОО.
Ну а я как разработчик проекта на несколько миллионов строк вижу очень много преимуществ в мультипарадигменности JS.
Заметьте: вы взяли одно предложение из моего комментария, а отвечаете на другое. Ответ на то предложение, которое вы взяли мог бы звучать так: «а я как разработчик проекта на несколько миллионов строк вижу очень много преимуществ в том, что у нас 10 разных эмуляций ОО в этих нескольких миллионах строк.»
Только ведь скорее всего это не так и вы обязаны использовать один единственный способ эмуляции ОО по внутреннему стандарту кодирования. Какой-нибудь y.inherit.
Попробуйте вот такой фокус на Дарт провернуть:
Было бы удобнее провернуть этот фокус, если бы вы объяснили конечную цель, конкретный пример использования. Потому что в зависимости от конечной цели я этот фокус по разному проворачивать буду. (Интересно еще пропустят ли вам такой код через ревью в ваш миллион строк и что будет написано в документации: расширяет один из классов в зависимости от фазы луны?).
Статическое приближение может выглядеть так:
class DerivedClass {
factory DerivedClass () {
return condition ? new _DerivedClass1() : _DerivedClass2();
}
}
class DerivedClassImpl { }
class _DerivedClass1 extends BaseClass1 with DerivedClassImpl
implements DerivedClass { }
class _DerivedClass2 extends BaseClass2 with DerivedClassImpl
implements DerivedClass { }
// new DerivedClass
динамическое приближение может выглядеть так:
class DerivedClass {
final base;
DerivedClass() : base = condition ? new BaseClass1() : new BaseClass2();
noSuchMethod(invocation) => reflect(base).delegate(invocation);
}
какое из приближений больше подходит по вашу конечную цель зависит от цели.
Я смотрю на вот этот туториал:
Давайте для начала уберем все фичи которые в JavaScript недоступны, оставив разве что интерполяцию, которая будет и в JavaScript в ES6.
class Greeter {
var prefix;
Greeter(prefix) { this.prefix = prefix; }
greet(name) {
print('$prefix $name');
}
}
понятно или непонятно? JavaScript код будет выглядеть а-ля
function Greeter(prefix) { this.prefix = prefix; }
Greeter.prototype.greet = function (name) { console.log(this.prefix + ' ' + name); };
какой код более явно говорит новичку: вот класс и вот метод? мне почему-то кажется, что первый. а потом можно шаг за шагам другие фичи накрутить (сокращенную запись конструкторов, именнованные конструкторы и тд).
Я вижу преимущества в мультипарадигменности. Я не вижу преимуществ в том, чтобы каждая вторая библиотека изобретала свою собственную несовместимую эмуляцию одной и той же парадигмы под названием ОО. Это перевод бумаги.
Dart на мой взгляд не менее мультипарадигмен чем JavaScript. Я даже могу нарисовать prototype chain на Dart, представляете? Только отличие от JS в том, что наиболее часто используемая парадигма — обычное советсткое ОО с классами — нет нужды рисовать, оно уже встроено.
Дарт не блещет ни особой понятностью, ни удобством разработки.
Можете привести пример «непонятности», так чтобы было менее понятно чем JS? Мне очень интересно.
лучше смотреть на TypeScript, который предлагает те же самые преимущества и нацелен на развитие JavaScript в web до ES6
Во-первых, не все в TypeScript — это ES6. Основная фича — система типов, это не ES6.
Во-вторых, основываясь на JavaScript, вы JavaScript и получаете на выходе со всеми вытекающими семантическими прибамбасами. Кому-то иногда хочется честной чистой семантики, а не винегрета.
А так, конечно, что нравится, от чего не тошнит, то и следует использовать.
Вот вы же замечательно иллюстрируете, зачем Dart нужен: называете кучу фреймворков и чество говорите, что объектные модели в них разные. (Даже в node.js, которая совсем почти не ОО есть util.inherits). Зачем? Какое в этом преимущество? Да никакого.
а потому, что он в чистом виде представляет собой попытку Гугла пересадить весь веб на его (Гугла) стек веб-технологий.
Нет, Dart представляет собой попытку предоставить разработчикам удобный инструмент разработки. Разработчик не цветок, который можно из одного горшка в другой пересадить лопаткой. Ему подавай преимущества и плюсы. Все остальное — это чистая конспирология из разряда «инопланетяне уже здесь, надевайте шапочку из фольги».
Лукавство я вижу в том, что мы наворачиваем абстракции на голый JS (OOP эмуляция и/или терминология, типы в комментариях), потому что это нам помогает в разработке, но при этом когда нам предлагают язык, в котором ничего не нужно накручивать и все и так понятно и работает, мы говорим «фу, да зачем! можно же жить за уровнями эмуляции». Мне это непонятно.
И обнаружил, что Balloon понимаешь ли «расширяет IDomEventEmitter». А если кликнуть на это, то дальше узнаем, что IDomEventEmitter он-то «расширяет IEventEmitter. интерфейс объекта, генерирующего „DOM-события“». т.е. вроде как классовоподобных фрейморков нет, а терминология имеется. Тут вам и конкретные объекты, и интерфейсы нарисовались, при том, что в самом-то JS никаких интерфейсов нет.
Возникает вопрос. Зачем лукавим? Почему столь антагонистичны языку, который предлагает: вот настоящие классы, вот настоящие аннотации типов (которые заметим в той же самой документации на API откуда-то получились, причем скорее всего из комментариев, а не из кода). Хочется настоящее наследование, одинаковое во всех либах, а не на ручной тяге где смысл слова «расширяет» меняется от либы к либе — пожалуйста. И т.д.
Особо инсайда тут нет, фокус действительно будет именно таким в первое время, что для VM, что для dart2js. Более компактный и быстрый код, меньше багов и моха :-)
Потому что философия такая. Хочется динамически типизированный язык программирования, на котором можно быстро прототипировать (типы под ногами не мешаются), но при этом с возможностью добавить типы для описания интерфейсов для средств разработки и т.д. Посмотрите в секцию Overview в том документе, на который вы сослались. Он эту философию описывает.
Ну почему, он вам покажет предупреждения, там где вы типизацию нарушаете, выбор ваш добиваться 0 предупреждений при компиляции или словить ошибку во время исполнения. Это полностью соответствует тому, что типы вообще можно не писать.
If you run a program in checked mode, the system will automatically execute certain type checks when passing in parameters, when returning results, and when executing assignments. If the checks fail, execution will stop at that point with a clear error message.
[...]
Essentially, checked mode is like running your program under the debugger with watchpoints that run a subtype check on every assignment, return, and so on.
Поверьте мне, я знаю как она работает не понаслышке, т.к. я работаю над Dart :-)
Я знаю. К сожалению, нигде не написано каким именно образом они это планируют. Основная проблема заключается в том, что непонятно каким образом «аннотировать» переменные составных / ссылочных типов. Для примитивных числовых типов они полагаются на coercions, а уже со строками возникает проблема. Аннотация в форме ""+a выглядит весьма сюрреалистично.
Моя позиция по отношению к asm.js проста: развивайте или JIT, или нормальные языковые средства (например, аннотации типов или статически типизированный байткод), или и то и другое вместе, но ради бога не нужно пытаться просунуть слона через игольное ушко под видом нитки.
Нет. Тут совершенно другая философия за Dart стоит: неправильная типизация не должна мешать вам запустить программу. Иными словами Dart все-таки динамически типизированный язык.
Вы действительно можете проверку типов вы включить (checked mode называется). Но работает она опять же во время исполнения. Если она включена T x; x = y; фактически превращается в T x; assert(y == null || y is T); x = y;, т.е. в примере выше при попытке вызвать bar(new Doge()) случится исключение, говорящее что Doge нельзя присваивать в переменную типа Point. Но оно случится во время исполнения, а не во время компиляции.
Конечно же, dart2js и dart_analyzer используют аннотации типов и сообщают вам предупреждения в местах, где вы нарушаете типизацию. Но предупреждения — это не ошибки.
class Point {
var x, y;
Point(this.x, this.y);
}
class Doge { }
bar(Point p) => p.x * p.x + p.y * p.y;
baz() => bar(new Point(1,2)) / bar(new Doge());
это абсолютно валидный Dart код, который при компиляции в JavaScript, конечно, ругнется что Doge это совсем не Point, но развалится-то он все-равно во время исполнения при попытке взять x с объекта типа Doge
Не совсем понятно, как asm.js поможет реализовывать «какие угодно языки». Прежде всего он ограничен в семантике самим JavaScript. Допустим хотите вы в свой язык добавить эффективный int64 или simd тип… JS нативно такого не поддерживает, как результат нужно сидеть и ждать пока TC-39 пропихнет такие типы в стандарт JS и пока их правильно и оптимально поддержат во всех реализациях.
Далее даже в рамках JS asm.js ограничен фактически арифметикой и работой с typed arrays. Иными словами, если вам допустим хочется реализовать язык со сборкой мусора, вам нужно реализовать сборщик мусора на asm.js. Попробуйте теперь с таким сборщиком мусора потягаться с GC встроенным в JS VM (который часто весь из себя параллельный и написан на вылизанном C++). Тоже самое относится к другим частям динамического языка: многие части реализации для пиковой производительности нуждаются с достаточно низкоуровневых примитивах, а asm.js не позволяет вам ни получить доступ к таким примитивам, ни опереться на реализацию JS VM, которая уже использует эти примитивы для оптимизации самого JS (как пример: inline caches для оптимизации доступа к полям).
к сожалению, написать leakless WeakMap shim невозможно:
var a = {}, b = {};
(function () {
for (var i = 0; i < 10000; i++) {
var map = new WeakMap;
map.set(a, b);
}
})();
var arr = [];
function A() { }
function B() { }
(function () {
var map = new WeakMap;
for (var i = 0; i < 1e3; i++) {
var x = new A;
arr.push(x);
map.set(x, new B);
}
})();
в обоих случаях память утечет (во-втором случае утечет B).
ничего особо weak или прорывного в хранении значений на ключе нет.
Оператор delete лучше вообще не использовать (за исключением очень крайних случаев), от него одно падение производительности. Еще он обладает таким интересным парадоксальным свойством (по крайней мере на V8), что после его применения объем занимаемой объектом памяти может возрасти (а не уменьшится).
Далее ведь я не обязательно хочу свойство удалять, я его допустим хочу обновить, а утечка все равно случится.
Дополнительное наблюдение, если вы пишете код в стиле:
var p = { a: 1, b: 2 };
var q = clone(p);
q.a++;
var u = clone(p);
u.b++;
some_f(q);
some_f(u);
где some_f работает с полями a / b, то some_f будет работать медленнее, чем она работала будь q и u созданы обычным конструктором, потому что они имею разные скрытые классы и как результат доступ к полям становится полиморфным.
смысл очень простой: asm.js вырос из emscripten, который фактически компилирует LLVM биткод в JS. Биткод работает с указателями и сырой памятью, но в JS указателей нет, поэтому память эмулируется типизированными массивами, которые все указывают на один и тот же ArrayBuffer, а указатели эмулируют целочисленной переменной. При этом поддерживается только правильно выравненные указатели, т.е. int16 должен быть выравнен на 2 байта, а int32 — на 4 байта и так далее.
Теперь если представить что i — это правильно выравненный указатель на double, то как прочитать double по «адресу» i? Надо взять Float64Array представление кучи и прочитать из него элемент с индексом (i / 8) (double занимаем 8 байт).
Отсюда и требование на сдвиг — это деление на размер элемента в преположении что остальное это «адрес», потому что emscripten всегда такой код рожает. В рукописном коде выглядит, конечно же, сюрреалистично
Ваш код на FF Nightly не проходит asm.js-верификацию c сообщениями типа
[12:43:56.056] TypeError: asm.js type error: non-expression-statement call must be coerced @ pi.js:91
(надо писать +floor, +pow везде)
А теперь внимание, сюрприз, производительность при этом у него не страдает. Как следствие, если взять и аккуратно переписать этот код на простой человеческий JavaScript получим ту же самую производительность и читаемый код
Странно называть функцию clone, когда она на самом деле не клонирует:
var a = { ref: HUGE_OBJECT };
var b = clone(a);
b.ref = null;
a = null;
// а HUGE_OBJECT-то утёк
Ну и в бенчмарке у вас замер «new constructor» замеряет совсем не то, что вы думаете — совсем даже не скорость создания объекта, а скорость присвоения свойства prototype (FF, Chrome страдают от этого, Safari — нет)
Если люди увидят достоинства Dart над JavaScript и большей частью пересядут на него, то в чем проблема? В амбициозности? «Через тернии к звездам» Надо стремится к светлому будущему, иначе оно никогда не настанет.
Как я уже говорил выше, я не считаю, что JavaScript может взять и исчезнуть по щелчку пальцами. Все решают массы и время. Демократия в чистом виде.
А где вы видите насильственную замену JS на Dart и «уничтожение JS»? Это такой мем, который возник на пустом месте.
Заменить JS полностью на Dart можно было бы только, если бы двое из ларца (одинаковы с лица) выскочили и за ночь переписали весь интернет и все браузеры :-)
Dart предлагает платформу, кто хочет пользуется. Кто не хочет — не пользуется.
показывая, что у Дарта нет никаких объективных преимуществ на JS
Вы показываете отталкиваясь от весьма субъективных критериев.
Для кого-то возможность получить исключение, а не undefined (или значение с Array.prototype!) при выходе за границы массива это уже преимущество. Точно так же, кому-то не интересно наворачивать снова и снова весь boilerplate связанный с prototype для того, чтобы выразить распространенную концепцию «вот объект он несет данные, а вот методы, которые с ним работают». Кому-то хочется сказать, что параметр x ожидается типа Foo и хочется выразить это знание прямо в коде, а не запихивать в jsdoc-комментарий.
Для меня, например, «аккуратная» и простая семантика, богатая стандартная библиотека (в которой многое унифицировано и причесано, например, парадигмы stream и future используются везде от клиентского dart:html до серверного dart:io), легко предсказуемая высокая производительность (достигаемая за счет гораздо более простой, и как следствие более стабильной и расширяемой VM), либеральная опциональная типизация — это все достоинства Dart.
Есть, конечно, и недостатки. Например, на мой взгляд Dart одновременно и недостаточно динамический (mirror builders должны улучшить ситуацию, но когда они будут специфицированы, не говоря уж о реализации не ясно) и не достаточно статический (и еще я бы предпочел поддержку non-nullable типов).
Языки программирования вещь очень субъективная, и меня всегда коробит, когда люди начинают обобщать их личные предпочтения и стиль разработки на большое число программистов. Я вот не обобщаю.
Положа руку на сердце, это вовсе не смертельные недостатки для языка программирования
Стоит отказаться от классовой парадигмы — и работа с JavaScript становится лёгкой и приятной.
мне как-то не приходят в голову динамические интерпретируемые языки
И он не производит впечатления простоты и понятности.
Может быть я читаю что-то неправильно, но это все совершенно явно ваша личная позиция, которую вы пытаетесь перенести на очень большой класс программистов.
Глупо было бы отрицать, что на свете много программистов, которые разделяют вашу точку зрения. Им нравится JavaScript со всеми его достоинствами и недостатками, и они не видят причины заменять его в повседневной работе чем-то другим.
Не менее странно, однако, утверждать, что все программисты должны довольствоваться JavaScript, а не стремиться к тем средствам разработки, которые удобны для них (а если они стремятся, то это «узкий кругозор» виноват!).
Справедливости ради стоит заметить, что там написано, почему Дарт не нужен вам. Вы довольны его семантикой, средствами разработки, доступными из коробки библиотеками и производительностью. Не совсем понятно как из этого проистекает ненужность Дарт кому-либо другому, кто не столь доволен JavaScript.
2424 это лишь один из многих. 2223, 2513, 2618, 2678, и т.д. Многие уже починены, но почему-то не закрыты: skinning например сейчас в пределах 5% от показателей OdinMonkey и >3x быстрее чем голый Ion Monkey, при этом V8 не полагается на «use asm» чтобы достичь таких результатов.
на наборе микробенчмарков V8 стал в среднем в 2-3 раза быстрее, на каких-то показывая скорость эквивалентную той, что дает Mozilla-вский AOT. однако еще много работы впереди. если вы напишите asm.js, который на V8 почему-то работает медленно — обязательно засылайте его в code.google.com/p/v8/issues/entry
лично для меня преимущество Dart в том, что это структурированный язык программирования, в котором есть привычные для большинства людей примитивы модульности, а семантика непозволяет прочитать undefined из-за пределов массива, а затем радостно помножить его с другим undefined прочитанным из несуществующего свойства или там сложить со строчкой «123».
к этому нормальному языку прилагается из коробки из коробки достаточно богатая библиотека которая покрывает и клиент и сервер, а еще есть пакеты реализующие вещи из будущего типа web components.
и при этом все это работает в любом современном браузере.
У V8 на самом деле есть ряд проблем с кодом, который emscripten выдает, многие из них правда asm.jsом не решаются, надо просто инфраструктуру чинить (например, проблемы при огромном количестве локальных переменных), некоторые решаются, но уж лучше их починить в общем случае (например, недостаточная хорошая протяжка информации о типах в пределах одного метода).
asm.js впрочем позволяет выделывать трюки, которые над обычным JS не так-то просто совершать: например, на x64 выкинуть все array bounds check и вместо это использовать перехват segfault для обнаружения доступа за границы кучи-типизированного массива.
У него есть проблемы с переносимостью, оно слишком низкоуровневое и быстренько сгенерировать из него хороший код не так-то просто.
Тут правда стоит заметить две вещи:
a) Emscripten генерирует JavaScript / asm.js как раз из LLVM IR (т.е. фактически asm.js это высокоуровневый переносимый формат для LLVM IR :-)),
b) Mozilla не сообщает накиках чисел о том, как быстро asm.js валидируется и компилируется (есть основания полагать, что там не все так радужно, David Herman даже писал, что они рассматривают вариант с кэшированием сгенерированного нативного кода).
Да предсказуемость, это, конечно, один из козырей asm.js и она действительно тот самый 1% бъет в яблочко на некоторых задачах. Правда бъёт она не в стиле «а мы тут немного затюним», а в стиле «а сейчас надо вычислительное ядро переписать на С++». Как по мне, так уж лучше бы мы эти 99% медленно превратили в 99.9%, а потом в 99.99% и так далее, чем сразу такая капитуляция.
Кстати, давно вас онлайн хотел поймать, была пара нубских вопросов по особенностям v8:)
А меня просто поймать, можно написать в личку или на почту me@mrale.ph (или рабочую) :-)