Comments 55
И в этой книге есть схема языков, которые повлияли на Go:
ALGOL60->C-Go,
ALGOL60->Pascal->Newsqueak->Alef->Go,
Pascal->Modula-2->Oberon-Oberon-2->Go
Так что идеи Вирта живут и здравствуют. Вместе с идеями Кернигана.
Другими словами, точка бифуркации была пройдена без Оберона. Хотя на Оберонах делались (и делаются) промышленные разработки.
Все библиотеки выполняются внутри виртуальной машины. Если эта виртуальная машина не поддерживает многопоточность, то никакая библиотека не поможет. От этого очевидного ограничения сильно страдают ruby, python, javascript, php. И никакие библиотеки не помогают.
Как толсто...
Лично я указатели в продакшн-коде вообще ни разу не использовал, потому что если они где-то и используются, то либо где-то очень глубоко в библиотеках для всяких некрасивых хаков, либо в интеропе с С/С++, хотя и там оберток Managed-кода вроде ref/out/IntPtr достаточно, чтобы снизить написание unsafe до 0.
Польза от множественного наследования будет нулевой только в том случае, если ты не умеешь им правильно пользоваться. Тогда да… будут только одни проблемы. Я в принципе согласен с тем, что использование множественного наследования требует более глубокого понимания ООП, чем обычно есть у тех, кто считает, что понимает эту парадигму. Но тем не менее отсутствие этой фичи уж точно не несёт никакой пользы, кроме защиты от дурака, который стремится пользоваться тем, чем не умеет.
В наши дни голые указатели и в С++ нечасто используются. Люди предпочитают оборачивать их в shared/unique_ptr. Хотя лично я считаю, что при программировании на безопасных указателях ощущения не те.
В наши дни голые указатели и в С++ нечасто используются. Люди предпочитают оборачивать их в shared/unique_ptr. Хотя лично я считаю, что при программировании на безопасных указателях ощущения не те.
Если только так.
Польза от множественного наследования будет нулевой только в том случае, если ты не умеешь им правильно пользоваться. Тогда да… будут только одни проблемы. Я в принципе согласен с тем, что использование множественного наследования требует более глубокого понимания ООП, чем обычно есть у тех, кто считает, что понимает эту парадигму. Но тем не менее отсутствие этой фичи уж точно не несёт никакой пользы, кроме защиты от дурака, который стремится пользоваться тем, чем не умеет.
Зачем сначала позволять множественное наследование реализации, а потом ломать себе голову, как ничего не отстрелить? Это детский подход, что шрамы украшают мужчину, а чем сложнее ЯП, тем элитнее на нем писать. Вон, можно посмотреть хаб PVS, там статистика подсказывает, что люди совершают элементарные ошибки в простейших местах, зачем расставлять грабли дополнительно? Какую выразительную силу это несет?
Вот покажите пример, что вот так вот с множественным наследованием реализации сделать изи, а вот с интерфейсным ничего хорошего не выходит.
Ну и ты так и не ответил на опрос, зачем наследовать МНОЖЕСТВЕННУЮ реализацию? Ведь можно наследовать как кучу интерфейсов, так и базовый класс. Зачем наследовать разную реализацию? Как раз с ООП множественное наследование плохо сочетается, как правило это все от хреново продуманной иерархии.
Множественное наследование же заставляет нас использовать реализацию, которую придумали разработчики языка.
Ну и да, если у вас одновременно объект — круг, и он еще и умеет в БД сохраняться, то это очевидное нарушение SRP.
Нарушения SRP нет в том случае, когда объект компонуется из двух базовых классов. Каждый класс отвечает за свой функционал. Ну, точнее, формально можно придраться к тому, что существует интегрирующий класс, но в жопу такие придирки. Лучше уж пусть такой класс будет. В нём можно реализовать что-то специфическое для данного конкретного сочетания базовых классов. Всё равно при необходимости это сделать в реальной задаче придётся сделать класс, который содержит в себе все те же базовые объекты в качестве членов. Но только ещё придётся нафигачить бесконечное число делегирующих методов, которые будут тупо пробрасывать вызов во внутренний объект.
Прямого доступа к памяти нет.
Его нет практически нигде в современных языках высокого уровня. Все почему-то пишут разные FFI. И они теперь все убогие?
Множественного наследования нет
Знаете, во многих языках вообще наследования нет. Например в Lisp-ах, и вообще в большинстве функциональных. Они убогие тоже?
Вам бы стоило понять, что есть языки, которые просто нужны для другого.Совсем для другого.
А намек на кучу других языков вы проигнорировали, или не уловили? Еще раз — прямого доступа к памяти нет в Haskell, например. И в Python. И в javascript. И что? И ничего. Это смешная придирка при наличии JNI/FFI.
Что до наследования — то оно прекрасно заменяется делегированием. И это всем известно, и никаких проблем не вызывает. Т.е. вообще никаких. А вот само множественное наследование их еще как вызывает.
Можно я спрошу просто — вы много языков-то знаете? Ну, таких на которых работали и работаете?
Ну вот при всем при этом, ваши претензии выглядят странно. Про те же библиотеки, скажем… Я не знаю других распространенных систем, где бы подключение сторонних библиотек было настолько же просто, как в языках на базе JVM. Фактически — добавить в проект ссылку на репозиторий — и уже можно работать. В Perl это сложнее. В Python — тоже сложнее, хотя и не сильно. Примерно на таком же уровне это в javascript. Поддержка сторонних компонент в IDE на порядки лучше — во многом благодаря той самой "неполноценной" рефлексии, которая позволяет видеть метаданные по классам без исходников.
А то что библиотеки друг с другом не стыкуются — так какая же это претензия к языку?
Опять же — Java это язык для другого. Скажем, сделать отчет на основе данных из базы, в формате Excel — это плюс одна-три зависимости, и 5 строк кода + шаблон в виде xls файла.
Библиотеки плохо стыкуются друг с другом ровно потому, что само ядро языка слишком ограничено. Почти для всего нужны библиотеки. В итоге авторов библиотек слишком много. Есть очень много библиотек, тупо повторяющих функционал других библиотек, но с немного другим интерфейсом. И практически никогда не получается выбрать такой набор, в котором бы библиотеки идеально подходили друг к другу. Кто-то возвращает списки объектов как ArrayList, кто-то другой — как SomeObject[], кто-то третий — как IList. Сплошной разброд и шатание. В результате, пользовательский код часто более, чем наполовину, состоит из циклов по перекладыванию из одного контейнера в другой.
Кстати, я согласен с тем, что Java — это новый Visual Basic. Только почему-то эта концепция не соблюдается. Очень часто можно увидеть её на серверах.
То, что библиотеки подключать просто, — это вообще ни при чём.
Да ладно ) То-то я видел тут (небольшую правда) кучку постов, о том что не надо тащить в проект лишние зависимости, потому что это трудно. В том-то и дело, что это реальная польза. У меня в текущем открытом проекте — 83 зависимости, и меня это совершенно не волнует. Не будет никакого геморроя — просто не надо тащить все в один проект, надо разбивать на сравнительно мелкие модули.
Почти для всего нужны библиотеки.
Вы не поверите — но это прекрасно! Главное что они не просто нужны — а они есть.
Что до остального — то опять же, с моей точки зрения это мелкие придирки. Да, можно List, можно массив, сейчас стало можно еще и Stream вернуть. Ну так извините, можно ведь и иначе взглянуть — можно вернуть имя файла (это String), можно Path (это уже немного другое, потому тут уже и структура папок в файловой системе, родитель, дети и.т п), а можно и просто File. И в чем же тут недостаток? Это разные вещи, для разных целей.
В результате, пользовательский код часто более, чем наполовину, состоит из циклов по перекладыванию
Ну это вы загнули… Arrays.asList(массив) — у вас этого половина? )))
Но в каком-то смысле — это правда. Потому что большая часть бизнес-кода — она реально из этого и состоит. Из базы в форму, из формы — обратно в базу.
вроде полноценной рефлексии
Что, простите? Это куда же она делась-то?
Видите ли, если вы с точки зрения скажем .Net смотрите, то да, где-то вы правы. Если с точки зрения других языков, где рефлексии вообще нет — то претензия непонятна. Более полноценная? А где вы ее видели?
И потом — это претензия слегка не по адресу. Она к erasure, а не к рефлексии. Глупо требовать давать доступ к тому, чего нет.
И еще — а можно спросить, зачем это вам? И почему вам не хватает скажем вот этого: https://github.com/google/guava/wiki/ReflectionExplained?
Видите ли, если вы с точки зрения скажем .Net смотрите, то да, где-то вы правы. Если с точки зрения других языков, где рефлексии вообще нет — то претензия непонятна. Более полноценная? А где вы ее видели?
Вы же сами сказали — в .Net-е. Да, мне с этой ТЗ странно смотреть на то, что считается рефлексией в джаве. Да, лучше, чем вообще без нее, но это и без моего высказывания очевидно.
И потом — это претензия слегка не по адресу. Она к erasure, а не к рефлексии. Глупо требовать давать доступ к тому, чего нет.
Ну так, собственно тезис можно свести к «без real-time дженериков полноценной рефлексии не получится». Хотя бы потому, что List<int> и List<string> это разные типы.
И еще — а можно спросить, зачем это вам? И почему вам не хватает скажем вот этого: https://github.com/google/guava/wiki/ReflectionExplained?
«А почему ви собственно спrашиваете?». Так диалог строить нехорошо :)
Тут налицо парадокс блаба. Зачем — ну тут много вещей, зачем. Например я использовал рефлексию для динамическоо построения наследника IComparer<T>, чтобы вручную постоянно не писать. Когда нужно сравнить 4-5 полей приходится писать кучу бойлерплейт-кода для этого. А так — просто перечислил поля для сравнения, вызвал метод GetComparer(), он динамически чик-чик, все типы проинспектировал, проверил что у них есть нужные методы (всё в рантайме, естественно), после этого сгенерировал код нужного класса, проистанцировал его и вернул в качестве результата. Т.к. класс после всего этого дела кэшируется то не считая первого вызова разницы в скорости никакой нет, а вот удобство использования повышается на порядок.
Вот тут немного тестов (и если интересна реализация — исходников), это пока что моя домашняя библиотечка, но возможно я когда её допилю сделаю на эту тему статью.
То, что такого нет в Java — это просто позор. При наличии интерпретирующей JVM сам бог велел предусмотреть хоть что-то для генерации байт-кода в рантайме.
для динамическоо построения наследника IComparer,
Ну это да, имеете право, хороший пример. Просто я обычно такие вещи пытаюсь решить на этапе компиляции, именно там где дженерики имеются в наличии (а еще есть аннотации).
Но вообще минус библиотек именно в том, что пользователь должен знать, как они работают. ну и иметь их. В данном случае это такой «костыль», который позволяет немного обойти эти ограничения, о которых я говорил.
Ну это да, имеете право, хороший пример. Просто я обычно такие вещи пытаюсь решить на этапе компиляции, именно там где дженерики имеются в наличии (а еще есть аннотации).
Я был бы рад, если бы подобные вещи можно было бы решить на этапе компиляции (я несколько завидую тем же constexpr из плюсов, в шарпах все рантаймово делается, даже если по идее компилятор может все это сам провернуть), но я лично не представляю, как именно. В данном случае пользователь может просто взять мою dll и использовать, для него лично ничего не поменяется — не надо использовать сторонние либы, (создавать токен на свои типы и передавать), не надо на этапе компиляции ничем заниматься — он может вообще, получить описание типа по сети (WCF), сгенерировать новый тип в рантайме, затем создать коллекцию этих типов и типобезопасно туда их складывать. И если внезапно придет объект другого типа на тот же эндпойнт, при попытке запихнуть его в коллекцию возникнет typemismatch. Это очень очень полезная фишка.
У меня это основной язык, и я в редчайших случаях сталкиваюсь с тем, что рефлексии мне почему-то не хватило.В этом и суть :) Вы не сталкивались, потому что у вас это основной язык, мне даже ничего добавлять не надо — это типичная зона комфорта. Мое личное мнение, что это плохо, т.к. развитие останавливается — экстенсивно оно идет, новые фреймворки/классы и т.п., но интенсив пропадает. В этом весь парадокс блаба:
Программисты старше определенного возраста редко меняют язык по своей воле. Они будут считать достаточно хорошим тот язык, к которому привыкли.
Программисты очень привязываются к своим любимым языкам, а я не хочу оскорбить ничьи чувства, поэтому я объясню свою позицию, используя гипотетический язык с названием Блаб.
Блаб попадает в середину континуума абстрактности. Это не самый мощный язык, но он мощнее, чем Cobol или машинный язык.
И на самом деле, наш гипотетический программист на Блабе не будет использовать ни Cobol, ни машинный код. Для машинных кодов есть компиляторы. Что же касается Cobol'а, наш программист не знает, как на этом языке вообще что-то можно сделать. В Cobol'е даже нет некой возможности X, присутствующей в Блабе.
Когда наш гипотетический Блаб-программист смотрит вниз на континуум мощности языков, он знает, что смотрит вниз. Менее мощные, чем Блаб, языки явно менее мощны, так как в них нет некой особенности, к которой привык программист. Но когда он смотрит в другом направлении, вверх, он не осознает, что смотрит вверх. То, что он видит, — это просто «странные» языки. Возможно, он считает их одинаковыми с Блабом по мощности, но со всяческими сложными штучками. Блаба для нашего программиста вполне достаточно, так как он думает на Блабе.
Когда мы поменяем точку обзора программиста, используя любой язык программирования выше по континууму мощности, мы обнаружим, что теперь программист смотрит на Блаб сверху вниз. «Как же можно что-то сделать, используя Блаб? В нем отсутствует даже конструкция Y!»
Используя метод индукции, приходишь к выводу, что только те программисты, которые понимают самый мощный язык, в состоянии осознать полную картину разницы в мощности между различными языками (видимо, именно это имел ввиду Эрик Реймонд, когда говорил о том, что Lisp сделает вас лучше как программиста). Следуя парадоксу Блаба, нельзя доверять мнению других: другие программисты довольны тем языком, который используют, потому что этот язык определяет способ их программистского мышления.
Ну вы же его (TypeToken) только что просили? :)
Называется, угадайте с трех раз, для чего вот это нужно:
TypeToken<List> stringListTok = new TypeToken<List>() {};
Что до генерации на этапе компиляции, то можно просто погуглить проект lombok, и поглядеть на живых примерах. Это конечно не сам компилятор генерирует, а annotation processors, но в данном случае это пофиг.
Что до остального, то я сказал основной язык, а не единственный ))) Мне например вполне комфортно на лиспе, без всяких преувеличений. И на Python тоже. И на многих других.
TypeToken<List> stringListTok = new TypeToken<List>() {};
даже не знаю, что бы это могло быть. Если судить по примеру, тут должно быть TypeToken<List<?>>.
Лисп кстати тоже бывает разный. Common например так себе, а вот диалекты вроде схемы уже съедобное. Хотя в любом случае сознание расширяет неплохо и классика :)
Вот что по этому поводу пишет Франк Солтис, создатель AS/400:
"… Язык программирования VLIC, называвшийся PL/MP и использовавшийся со времен разработки оригинальной System/38, был основан на языке PL/I. MP в его названии расшифровывается как Machine Product — имя, которое часто использовалось для обозначения аппаратных средств и обоих слоев микрокода. Компилятор PL/MP, как и ассемблер IMPI, генерировал двоичные машинные команды IMPI.
… В течение ряда лет мы пытались использовать другие языки при разработке компонентов VLIC. Например, один из наших новейших трансляторов был написан на Modula-2, применялся также язык С. Однако, мы чувствовали, что ни один из них не подходит для проекта, основанного на объектно-ориентированной технологии. Выбор напрашивался сам собой — язык C++. Нам нужно было разрабатывать код ОС очень низкого уровня. Иногда, для достижения оптимальной производительности приходилось прибегать к ассемблеру, и С+ + легче позволял это. Ведь, фактически, язык С++ и есть современный вариант ассемблера…
Технология ООП не подвела: производительность программистов при разработке SLIC повысилась почти в четыре раза по сравнению с традиционной методикой. В период с июля 1992 года, было создано более миллиона строк кода на С+ + и более 7 000 классов.… "
Ф. Солтис, «Основы AS/400».
Не Паскалем единым: что сделал для современного мира лауреат компьютерной «нобелевки» Никлаус Вирт