Pull to refresh
95
0
Вячеслав Егоров @mraleph

Пользователь

Send message
Что как раз очень правильно в плане обучаемости программистов


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

Но в 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, что и браузерный код.

я бы честно говоря предпочел coroutines.
Я не вижу преимуществ в том, чтобы каждая вторая библиотека изобретала свою собственную несовместимую эмуляцию одной и той же парадигмы под названием ОО.
Ну а я как разработчик проекта на несколько миллионов строк вижу очень много преимуществ в мультипарадигменности 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 эмуляция и/или терминология, типы в комментариях), потому что это нам помогает в разработке, но при этом когда нам предлагают язык, в котором ничего не нужно накручивать и все и так понятно и работает, мы говорим «фу, да зачем! можно же жить за уровнями эмуляции». Мне это непонятно.
> Ну, мы в API Я.Карт не используем никаких классовоподобных фреймворков

Я ради интереса даже пошел посмотреть как эта документация выгладит. Открыл

api.yandex.ru/maps/doc/jsapi/2.x/ref/reference/Balloon.xml

И обнаружил, что 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 используют аннотации типов и сообщают вам предупреждения в местах, где вы нарушаете типизацию. Но предупреждения — это не ошибки.
т.к. все проверки он выполняет в compile-time


это не совсем так или даже совсем не так

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 созданы обычным конструктором, потому что они имею разные скрытые классы и как результат доступ к полям становится полиморфным.
А как вы эту программу собирали? Допустим если я собираю как

$ gcc -o pi -O3 -m32 -msse4 -mfpmath=sse pi.c


то особой разницы не вижу

$ time ./pi
 position = 10000000
 fraction = 1.480308905010555
 hex digits =  7AF5863EFF
./pi 10000000  20.38s user 0.01s system 99% cpu 20.391 total

Information

Rating
Does not participate
Location
Дания
Date of birth
Registered
Activity