Comments 353
'0', 0 и 0.0 являются неправильными, но '0.0' — правильным.
Оператор === устраняет эту проблему при неприведении типов данных, но вводит в заблуждение, будучи происходящим из других языков.
должно быть "… вводит в заблуждение приходящих из других языков" (программистов).
чтобы ваше основание логарифма было 10:
«основание системы счисления» — на этом я перестал читать перевод.
T Plus<T>(T t1, T t2)
{
return (dynamic)t1 + (dynamic)t2;
}
Можете так же посмотреть на Scala, если у вас есть выбор. Там у операторов нет привелегированного положения и они являются обычными методами, что позволит сделать generic-метод с нужными constraints.
Там у операторов нет привелегированного положения и они являются обычными методами, что позволит сделать generic-метод с нужными constraints.
Операторы в C# — обычные методы operatorX. Параметр generic-метода без всяких constraints имеет методы Object (ToString, Equal, GetHashCode итп). Сравнения, операции, другие методы — все надо делать через constraints определенного интерфейса. Например, сравнение — IComparable. Но интерфейса для математических операций нет. Да и примитивные типы являются по-сути структурами, а не классами, поэтому даже IComparable тут не канает.
P.S. Случайно узнал, что Array.Sort как-то работает даже с T[] без всяких ограничений.
разве не решает проблему?
Да там даже IDisposable не в тему. Давно же уже договорились, что при правильной архитектуре полный Disposable-паттерн не нужен.
Если класс непосредственно владеет только управляемыми ресурсами — достаточно простой реализации интерфейса. А если он владеет неуправляемым ресурсом — его надо наследовать от SafeHandle. Любая другая реализация может привести к утечкам памяти при выгрузке домена приложения.
неудобных делегатов (broken by design!)
А что в них неудобного? Я особенно сильно страдал, когда пришлось одно время писать на Java и делегаты (и события) просто рай земной.
бредового доступа к памяти и массивам (планируется улучшить в виде Memory Span API)
А вот это сильно интересно. В чем бред?
null
, тогда через рефлексию выясняется, как вызывать метод, поэтому делегаты такие медленные. У делегатов может быть не одна пара контекст-метод, а несколько. Делегат без таких пар превращается в null
. У делегатов нет структурной эквивалентности и наследования друг от друга, т.е. EventHandler
и Action<object, EventArgs>
это совершенно разные вещи. Короче говоря, лучше чем в Java, но хак на хаке и могло быть гораздо удобнее.Про доступ к памяти я могу писать бесконечно. Например, почему нет read-only array? Почему String и char[] это разные вещи с разными API? Почему разые API используют массивы, строки, указатели, IntPtr, что угодно из предыдущего плюс start index и length, иногда даже IEnumerable, но не единый способ доступа к памяти? Почему существует ArraySegment, но он нигде не используется? Почему я не могу превратить часть строки в число и обратно без миллиона аллокаций? Почему есть OffsetToStringData, но нет аналога для массивов? (Ответ: потому что массивы это один большой «особый случай» для среды исполнения и языков.) И я ещё не начинал про SZArray! Это всё начинают исправлять с внедрением Memory Span API. Надеюсь они доведут дело до конца и переделают большинство стандартной библиотеки на нормальные аргументы.
String и char[] — это разные вещи потому что первый неизменяем. А StringBuilder и char[] — это ращные вещи потому что у первого переменная длина. Часть строки превращается в число и обратно при помощи всего одной аллокации, а не миллиона.
Почему String и char[] это разные вещи с разными API?
Потому что строки — иммутабельные объекты (поэтому нет методов работы как IEnumerable) и имеют (внезапно) своим методы по работе со строками (не C все-таки).
С остальным в принципе соглашусь, но в 95% случаев (на вскидку) используются различные реализации IEnumerable, а точнее — массивы и System.Collections.Generic
Надеюсь они доведут дело до конца и переделают большинство стандартной библиотеки на нормальные аргументы.
И сломают кучу-кучу-кучу-кучу существующего кода?
Проблема в том, что различные API требуют char[] или string, хотя им нужно гораздо меньший контракт, чем предоставляют char[] или string. Они вынуждены поддерживать оба класса, потому что для потребления они эквивалентны (даже имеют бинарную совместимость), но типа с подходящим контрактом попросту не существует.
Возьмите конструктор строки: вам на самом деле требуется всего лишь указатель, длина, кодировка для создания строки, а не 8 оверлоадов. Это всё можно схлопнуть в два-три варианта конструктора с ReadOnlySpan.
Возьмите TextElementEnumerator, он оперирует исключительно на строках, делая огромное количество аллокаций, хотя единственный контракт, требуемый ему от типа string – это неизменяемость. ReadOnlySpan избавит вас от мучений.
В 99% случаев, когда используется массив в качестве аргумента, тип массива не подходит. Возьмите класс Array – все методы, кроме Clear, SetValue, Reverse, Sort, не должны принимать массивы в качестве аргументов. И опять ReadOnlySpan спасет.
А ещё поддержку UTF-8 строк мешает сделать именно вот такой изначально плохой подход к работе с памятью. Основной вариант сейчас это распознавание отдельных опкодов в существующих программах и изменение их для более корректной работы с памятью.
Как выбирают
Javascript: И фронт и бек на одном языке, ну наконец то.
PHP: В моем городнейм 120 вакансий ит, 110 по php, без хлеба с маслом не останусь.
Java: СМАРТФОНЫ = ANDROID! ANDROID = СМАРТФОНЫ!
Obj-C: Я что зря накопил на макбук и айфон.
С++: ОБОЖАЮ ИГРЫ. Отправил резюме в еа, убисофт, и т.д.
C#: Прикинув силы реально, попробую на Unity.
С: Я использую Линукс, или как я недавно начал говорить Гну слэш Линукс.
Как не выбирают язык
pony() + (!((f{}=try(a(a+b==(!x.magic%n)))/(/friend/*)::bool(1)))) // Вот так не работает, а ведь должно!
По основной статье — справедливости ради отсюда бы поубирать придирки к стилям именования а также болячки ранних версий языков. У того же Руби в 2 раза тогда сократится список «болячек». На самом деле, какая разница что было в 2007-м с языком, если сейчас в том же 2.3.1 большая часть претензий уже не актуальная. Что касается придирок по upcase и downcase — вообще вкусовщина странная. Если уж так нужно, руби позволяет применять манки-патчинг к кор-методам и классам, так что при желании за пару строк можете себе сделать хоть метод toUpperCaseForMePlease и это будет работать. А если совсем тяжелый случай — оформляете эти горе-методы в свою либу (тоже всего несколько строк) и инклудите в свои проекты (главное чтобы на гитхабе не увидел никто). В свое время поступал так с округлениями при переходе с 1.9 на 2.0, писал манки-патч умещающийся в один 6-ти-строчный гист.
И много фактических ошибок. Мелких, но показывающих поверхностное знание предмета.
Например: «любой php код, даже не генерирующий html, должен быть заключен в <?php… ?> » — закрывающая скобка мало того, что необязательна, так ещё и обоснованно считается довольно серьёзной ошибкой.
для примера
isNaN('asd') //вернёт true, хотя 'asd' это строка а не NaN
Number.isNaN('asd') //вернёт false, что на мой взгляд более верно
isNaN(s) проверяет является ли s «не числом» явно или не явно (в виде строки)
Number.isNaN(s) проверяет является ли s именно значением NaN
Обе функции дают правильный результат, но смысл у них немного разный.
Выражение if isNaN(a) соответствует «если a не число», что логично, на мой взгляд.
Ваша задача не соблюсти формальность, а сделать так, чтобы программист, использующий вашу библиотеку не ошибся по той или иной причине. Ваши оправдания никак этой цели не соответствуют.
Более того, не рекомендуется использовать отрицание в названии функции. Лучше сделать функцию isNumber().
Может, это правильно, когда при попытке вызова
isNan(string)
язык возвращает не true и не false, а exception?NaN
в данном контексте ни разу не отрицание, это просто название специального значения. Для isNumber
было бы ожидаемо давать ответ на вопрос «тип аргумента — число?» и isNumber(NaN)
, соответственно, должно выдавать true
: NaN
в системе типов это число.
В данном контексте это как раз не «специальное значение NaN». Оттого и спор.
Даже в данном контексте это «специальное значение». isNaN(x)
— это как Number.isNaN(+x)
, Number.isNaN(x)
— это typeof x === 'number' && isNaN(x)
. Что‐то вроде предложенного ниже convertsToNaN
было бы, конечно, более однозначным названием, но это всё ещё проверка на то, не является ли x
специальным значением, хотя и в контексте, в котором x
будет приведено к числу. Никакого отрицания тут нет, потому что NaN
— тоже число согласно системе типов. Отрицание было бы, если бы при приведении генерировалась ошибка, и тогда название isNaN
было бы весьма странным.
С тем, что названию лучше бы быть другим я согласен. Но с тем, что «другим» значит !isNumber
— нет, равно как и с тем, что в названии isNaN
есть отрицание. В частности, convertsToNaN
было бы адекватнее, но, вообще‐то, пока унарный плюс не бросает исключений (кстати, а он при каких‐то условиях бросает, при которых isNaN
— нет?), ни isNaN
, ни convertsToNaN
не нужны при наличии Number.isNaN
.
В JS вообще функции в первую очередь реализуются с неявным приведением (==, и только потом ===), а большинство и вообще не имеет аналогов без приведения. «false».endsWith(false) === true.
Так же и isFinite(«123») === true, a Number.isFinite(«123») === false.
Называть это проблемой — преувеличение. И эти пара добавленных функций — просто сахар, избавляющий от проверки типа, если(!) для вас важно выделять именно NaN, который в вашем коде каким-то образом может приходить вперемежку со строками.
typeof(a) === "number" && isNaN(a)
против
Number.isNaN(a)
Вы же не с (тоже предполагаемой) функцией „isNumber“ сравниваете.
Хотите проверять без приведения? Пишете x!=x, экономите четыре символа.
Ваш переводчик — отстой.
Есть попытка, но не окончательно
Не сразу понял, что речь о try и finally.
https://goo.gl/5qAzXE
В любом случае, получилось очень колко.
Как Оберон — отдельный диалект Object Pascal.
Оберон намного сильнее отличается от Паскаля, нежели Delphi.
Но наверняка Delphi отличается от Паскаля намного сильнее, чем C# от C# :)
Но не сильнее чем C# от Visual Studio!
С# всё-таки язык программирования, а Visual Studio — среда разработки. А Delphi c Pascal оба — языки программирования.
Эдак можно договорориться до того, что С# от Ворда отличается сильнее, чем Delphi от Pascal :). И, что характерно, утверждение будет верное :)
А зачем ему меняться, если он как раньше VBA редактировал, так и сейчас?
VB же всегда был отдельным языком программирования, пусть и похожим.
«А твой любимый язык настолько отстой, что о нем даже писать неохота, это очевидно!»
Судя по
Несовместимость браузеров Firefox, Internet Explorer, Opera, Google Chrome, Safari, Konqueror и т.д. делает работу с DOM чрезвычайно трудным делом.
статья писалась тогда, когда Swift ещё не было или он только-только появился.
Это о Array и Map, видимо.
У Rust есть исключения.
Ну вот, только на ЛОРе закончился срач. :) Нет в Rust исключений. Исключение это механизм сообщения об ошибке, который выкидывает управление из функции по стеку до ближайшего обработчика. Исключение не трогает объекты программы и предоставляет обработчику решать что делать дальше. Паника же — средство контролируемого уничтожения потока, в котором она произошла. Паника вызывает деструкторы. И то, что её можно перехватить и некоторым шаманизмом сохранить поток не делает её исключением. Объекты всё равно придётся создать заново.
Фактически разница между исключением и паникой такая же, как между реальным марафонским забегом с сообщением о проигранной битве и тем же забегов в исполнении Голливуда, когда прямо за пятками бегуна вспухают пламенные взрывы и рушится земля.
Две реализации случайных чисел — math/rand и crypto/rand
Забавно. В основном все прочитал мельком, а за это прям глаз зацепился. Прям выбивается из всей этой вкусовщины и вбросов.
Да ни чем оно не выбивается. Такая же глупость как все остальное. Подобное разделение есть в любом озяке общего назначения.
А что действительно непонятно, это причина минусов. Кто-то еще что ли не знает, зачем именно две разных реализации нужны или что?
Что это за высер промпта из начала 2000-х?
ничто, кроме GCC и шумихи,
Убило наповал
Много воды, косноязычия и банального непонимания соответствующих языков. Также большое количество придирок к языкам по своей природе в точности сооветствуют известному анекдоту, где некто жаловался на то, что из его окна открывается вид внутрь помывочного отделения женской бани — надо только на шкафчик залезть.
Также:
Язык С
Автоматическая инициализация переменных в нуль не происходит, хотя они являются статическими, поскольку «это более эффективно».
Это вранье. Все статические объекты в С инициализируются нулями по умолчанию.
Язык С++
Он имеет обратную совместимость с С.
Нет.
Однако имеются небольшие различия, из-за которых некоторые C-программы не удаётся скомпилировать компилятором C++.
Различия С и С++ — огромны и фундаментальны. С — lvalue-discarding language, C++ — lvalue-preserving language. Уже этого достаточно для того, чтобы заявлять, что любые сходства между этими языками — не глубже уровня сходного синтаксиса.
Вызовstd::string::c_str()
требуется для преобразованияstd::string
вchar*
. Из самого мощного языка мы всегда имели бы полностью принимаемый перегруженныйoperator const char* () const
.
Косноязычие не позволяет понять, что именно имеется в виду.
Разработчикам, возможно, придётся побеспокоиться о вопросах оптимизации, таких как, например, объявлять функцию inline (встраиваемой) или нет; но после принятия такого решения оно является только предложением: компилятор может решить, что предложение неправильное, и не принять его. В чём смысл? Должны ли разработчики беспокоиться о вопросах оптимизации?
Уже давно было объяснено, что inline
больше не имеет отношения к оптимизации. Этот спецификатор влияет лишь на то, как определение функции взаимодействует с One Definition Rule, и не более ни на что. В С++17 появятся inline-переменные, где новая роль inline
сияет во всей красе.
Это вранье. Все статические объекты в С инициализируются нулями по умолчанию.
Это реализации, по стандарту инициализация не предусмотрена. Впрочем, может я и упустил нововведения, потому сильно спорить не буду.
Различия С и С++ — огромны и фундаментальны. С — lvalue-discarding language, C++ — lvalue-preserving language. Уже этого достаточно для того, чтобы заявлять, что любые сходства между этими языками — не глубже уровня сходного синтаксиса.
Теперь — да.
Но вообще, для С ниша на сегодня понятна. А С++ — действительно стал монструозен… Но опять же, это сугубо лично моё мнение, и я его ни в коем разе не навязываю.
В своей работе я использую лишь подмножество С++, наиболее понятное и очевидное. Этим я занимаюсь уже много лет, но ни разу язык не поднялся называть себя программистом С++.
> 6.7.8 Initialization
> 10 [...] If an object that has static storage duration is not initialized explicitly, then:
> — if it has pointer type, it is initialized to a null pointer;
> — if it has arithmetic type, it is initialized to (positive or unsigned) zero;
> — if it is an aggregate, every member is initialized (recursively) according to these rules;
> — if it is a union, the first named member is initialized (recursively) according to these rules.
1) Массивы C++ — std::array.
2) Желаю удачи с неявными кастами из\в void*.
Проще различать их как vector — данные в куче, array — данные на стеке. Соответственно размер array изменить нельзя.
любое изменение размеров vector'а может привести указатели на произвольные элементы вектора в негодное состояние
Вовсе не любое, а только такое, после которого «new size is greater than the old capacity».
realloc() тоже делает все указатели на элементы в памяти невалидными, но он таки выделяет память под массив, динамический, в куче… это я точно не про vector сейчас?
они совершенно не интересуются, массив это или нет.
Естественно, ибо ни железяка, ни рантайм, ни что-либо ещё не знает о существовании каких-то массивов о которых говорит эксперт с хабра.
Типы — это свойство интерфейса. На этом уровне — указателя.
блоками памяти
Школьное название, но ладно. Удивлю, но память и есть массив адресуемых элементов. Опять же на уровне языка этого нет.
Не забывайте, *alloc принимают не число элементов, а размер в байтах
А что такое байт? Это не элемент?
realloc завершается успешно, даже если из ста элементов удалось переместить 3,141592. π скопированных элементов — это нормальное поведение массивов?
Чё? Если вектор на аппенде зафейлится, то чем его поведение будет отличатся от реалока?
На адекватном уровне типизации — нет.
Типизации на уровне памяти не существует, ибо память никакого отношения к языку не имеет. Типизированным может быть только интерфейс.
Рассматривать любой объект (так, как он определяется в стандарте) как массив байт и исходя из этого определять понятие массива можно, конечно, но представляется неконструктивным.
Опять какая-то брехня. Какой ещё объект? В памяти нет никаких объектов. Память это и есть массив адресуемых елементов.
Без разницы что это байт или не байт. Просто по умолчанию принято, что байт это минимальная адресуемая единица в памяти. Но это не всегда так.
Т.е. если мы имеем какой-то адрес и его длину( т.е. блоками памяти по вашему), то на самом деле мы имеем массив из всех значений от значения адреса текущего до значения адрес + длинна.
Всё просто.
И без разницы как это дальше интерпретировать — память это массив. По определению.
На уровне памяти и массивов не существует. На уровне памяти вся память — один большой единственный массив.
Ой балаболка. Дак память массив или не массив? Ну ладно тут лужа.
А теперь подумаем, о чём же мы говорили? Ой мы говорили о:
блоками памяти
Т.е. кусок массива( блок есть кусок) не является массивом? Вот это новость.
Объект — это, если сильно упрощать, вот эта самая адресуемая штука. int a; struct {} foo;, и так далее.
Не верно. Объекты существует на уровне языка — это интерпретация памяти. На уровне памяти же никаких объектов не существует.
Собственно на этой логике построены юнионы. Ну куда там балаболам.
Вы не можете так относиться в памяти к C++.
Опять какие-то пустые утверждения. На основании чего вдруг я не могу? Поподробнее.
А объекты вы через memcpy копируете? Даже с виртуальными функциями и всем таким? Норм вам тама.
Какие такие объекты? Причём тут объекты. Говорилось про «блок памяти» — блок памяти есть массив. С этим вы выше согласились. Зачем эти ваши потуги? Какое они имеют отношения к теме?
Да, объекты копируются мемкопи — любые. И объясняется этот факт очень просто. Вы там выше балаболили про new, дак вот как работает new? Правильно через sizeof.
Т.е. при создании объекта он создаётся в «блоке памяти», который явно определён. И этот блок ничего не мешает копировать.
Тут вы пытаетесь слиться на тот факт, что виртуальные(как и любые) куллстори это могут быть не только данные, но и какая-то левая логика. Но потуги не имеют смысла, ибо левая логика не есть данные и не есть память.
При это какое отношения имеет ваш высер к той цитате на которую вы отвечаете — вы не ответите, ибо он отношения не имеет.
Заметим. Высер аналогичный той тактике, что я описал в каком-то комменте. Мы высираем какую-то не относящуюся к делу херню и на основании «потому что я так сказал» делаем вывод, что «оппонент дурак».
Только не сливайтесь, пожалуйста, что рассуждаете про совместимое с С подмножество С++, это бессмысленно.
Балаболка пытается меня ловить на том, что я якобы куда-то сливают. Можно мне доказательства?
На уровне процессора и ассемблера — массив байт. На уровне языка — нет.
На уровне языка так же. В целом споры с балаболами лсными бесмысленны — зачем я этим страдаю?
На уровне языка память никакой типизацией не обладает. Собственно поэтому аллокаторы и возвращают void *.
Типизация памяти является свободной — это определено на уровне языка. У памяти есть только свойство «длинна» и начальный адрес. По определению понятие адреса и длинные( опять же в языке длинна является ничем иным как офсетом между началом и не включенным конечным значением) представляют множество всех значений. По умолчанию используемой единицей адресации на уровне языка определён char, а на уровне модели памяти любое значение числа в промежутке «между» допустимыми.
Да, и эту логику юнионы инкапсулируют (и, кстати, поговаривают, писать в один член юниона, а читать из другого — UB). Но инкапсуляция — для балаболов, чоткие пацаны смешивают понятия, ясно.
О боже, опять какой-то убогий высер.
Чтение и записать в любые члены юниона не является уб. Ты получишь ровно то, что там есть. Это валидная операция.
Балаболка балаболит про УБ уровня представлений данных. Это уб следствие того, что представление типов данных в языке не определено. К памяти отношения не имеет. К возможности её чтения то же.
Потому что копировать объекты через memcpy вы не можете, например.
Какие такие объекты? Мемкопи копирует память. Копировать представление в памяти любого объекта я могу.
В целом потуги ясно. Балаболка обосралась и пытается съехать с темы памяти и объектов в памяти на тему объектов в логики смеси данных и исполняемой логики.
Только штука в том, что исполняемая логика к мамяти отношения не имеет. Как и формат и представление объектов записаных в память.
Вон из профессии.
Убогая ламрюга. Как это прекрасно, когда обосравшийся балабол начинает съезжать на левые понятия, а потом что-то из себя строит.
Мешает семантика языка и наличие конструкторов копирования, которые надо вызывать. Копировать вы можете только POD-типы (в C++03, в C++11 чуть сложнее).
В целом слив пошел по тому пути, что я заранее определил.
Какое отношение семантика языка имеет к памяти?
Этот тред тому доказательство, юное создание.
Действительно. Что-то на основной мой пост ты не ответил. А теперь как и любая балабокла пытаешься юлить, в чём-то меня обвинять и прятаться за таких же лсных балаболов как ты.
Ничего удивительного в этом нет. Из таких убогих состоит людей помойка.
Напомню, что у функций Си в параметрах элементарные типы, либо структуры, либо указатели на них. Вызвать printf с первым параметром типа FILE получится после изнасилования компилятора. Да, си, а вслед за ним и С++ позволяет насиловать как компилятор, так и железо непосредственно, но нисколько не поощряет такое поведение.
> Удивлю, но память и есть массив адресуемых элементов.
На уровне железа? На уровне железа, раз уж вас так сильно тянет вниз, у нас есть блоки SDRAM или других типов, которые не обязательно имеют один размер, не обязательно имеют сплошную или одномерную адресацию и не обязательно являются непрерывными. На уровне ОС? Блоки (да что-же за школьное слово-то!) виртуальных адресов, проецируемых на те самые физические адреса. Уже на уровне ОС память не является одномерным массивом, так как несколько приложений способны иметь одинаковую локальную виртуальную адресацию, которую ОС распихивает и разгребает.
> Опять же на уровне языка этого нет.
Ну давай, завкаф филфака, удиви, что же есть на уровне языка?
> А что такое байт? Это не элемент?
Нет, если у меня массив int.
> Чё? Если вектор на аппенде зафейлится, то чем его поведение будет отличатся от реалока?
Выбрасыванием исключения std::bad_alloc? Не знаю… Чем же такое поведение отличается от ошибки выделения памяти в том же Питоне?
Напомню, что у функций Си в параметрах элементарные типы, либо структуры, либо указатели на них.
Вот это новость. Меня тутошние эксперты учат Си. Как это мило. В функцию передаются аргументы через копирование. И отсутствие передачи массивов, функций и прочего — это свойство не функций, а некопируемости этих объектов. Так работает присваивание в си, что присваивание некопируемоего объекта равняется присваиванию указателя на оный.
Такая же логика работает везде и поведение функций есть следствие этой логики.
Вызвать printf с первым параметром типа FILE получится после изнасилования компилятора.
Чего? Поподробней про насилие при передачи указателя.
На уровне железа?
На уровне того, что там указано. А раз иного не указано, то уровень того о чём собственно говориться — т.е. си, да и в целом программном уровне. Ибо любая программа работает на этом уровне и ничего снизу к ней отношения не имеет.
Тем более опять же память имеется ввиду на том уровне, о котором опять же говорил изначально эксперт. Т.е. представление памяти и её адресации на уровне предоставляемом железякой программе интерфейса.
На уровне ОС? Блоки (да что-же за школьное слово-то!) виртуальных адресов, проецируемых на те самые физические адреса. Уже на уровне ОС память не является одномерным массивом, так как несколько приложений способны иметь одинаковую локальную виртуальную адресацию, которую ОС распихивает и разгребает.
Из этого ничего не следует. Зачем мне об этом рассказывать? От этого этого определение памяти не меняется.
Память есть набор(последовательный — т.е. массив) адресуемых единиц. Что собственно стоит за этими единица, существуют ли они вообще и в каком виде — это не важно. От этого ничего не изменится.
Это верно и для уровня ОС и для уровня приложения. «блоки» на уровне ОС есть ни что иное как объект уровня менеджмента, а не памяти. В любом случае всё это в конечном итоге эмулирует то определение памяти, что я дал.
Точно так же и процессор эмулирует для ОС определение памяти, что я дал. А далее это уже уровень не программный.
Ну давай, завкаф филфака, удиви, что же есть на уровне языка?
Зачем мне задан этот вопрос? Из чего он следует?
Может не ясно почему логика рантайма и логика программиста не являются уровнем языка?
Нет, если у меня массив int.
Опять 25. Что за тотальный аутизм. Массив, а в данном случае указатель — есть интерфейс, а не память. Нет никаких различий между int и не int на уровне памяти. По определению и языка, и матчасти и логики.
Выбрасыванием исключения std::bad_alloc?
Опять какая-то ахинея вместо ответа. Вы написали херню:
realloc завершается успешно, даже если из ста элементов удалось переместить 3,141592. π скопированных элементов — это нормальное поведение массивов?
Мало того, что это какая-то херня, да и к тому же вы написали «это нормальное поведение для массивов?» — т.е. намекая на ненормальное поведение.
Вас спросили чем это поведение отличается от «массива» вашего. Вы ответили «не знаю». О какой вообще вашей вменяемости может идти речь? Если вы не знаете — нахрен вы это пишите?
Так работает присваивание в си, что присваивание некопируемоего объекта равняется присваиванию указателя на оный.
Да ну?
int a[10], b[10];
a = b; // error: assignment to expression with array type
Капитан Очевидность сообщает: некопируемый объект — он реально некопируемый.
Вы не поняли. Я знаю, что везде передаются указатели. Но на уровне языка передаются указатели на тип. Не абстрактный адрес, а вполне конкретные свойства объекта. Если типы структур или сигнатуры методов не совпадают, компилятор выдаёт ошибку. Компилятор. Вы можете подавить его, заставить быть тупой железякой. Но из коробки он весьма умный и въедливый парень.
> Чего? Поподробней про насилие при передачи указателя.
http://coliru.stacked-crooked.com/a/f200471b2d6ca492
> Зачем мне задан этот вопрос?
>> массив адресуемых элементов. Опять же на уровне языка этого нет.
Я просто поинтересовался, как же так, на уровне языка нет массивов, если есть operator[]?
> По определению и языка
http://coliru.stacked-crooked.com/a/45b48688dc07146a
Не сходятся концы.
> ахинея
Мне очень жаль, что машинный текст не способен передавать интонации голоса, как способен это делать рукописный. Последние два предложения следовало читать с саркастически-издевательской интонацией.
Я действительно не знаю, как питон даст знать об окончании памяти, но я точно знаю, что после неуспеха выделения памяти вектор отменит эту операцию, не потеряв ни одного из уже имеющихся элементов. И тем более, не будет мне петь «Всё хорошо, прекрасная маркиза...», скопировав мне три с половиной землекопа. Для меня очевидно, что на уровне языка корректно только такое поведение.
realloc же его нарушает, что даже с точки зрения языка Си не очень корректно, и именно это заставляет си-программистов каждый раз бить его по голове операторами явного приведения адреса памяти к указателю на тип. Хорошо, что у плюсовиков такой проблемы нет…
Структуры, аналогичные std::vector по свойствам, часто называют динамическими массивами.
Т.е. взяли си. Нахлабучили на него классы макросами, потом уже на уровне компилятора. Далее нахлабучили шаблоны, которые опять же не на уровне языка( они ничего не знают про сущности языка — они просто тупо занимаются подстановкой), а новый уровень(т.е. новый язык поверх языка в котором опять же кастылят свои функции, свои циклы и прочее) просто поверх. Т.е. если в сишке бахнули поверх языка препроцессор, то шаблоны есть ни что иное как тот же самый импрувнутый препроцессор. Только уже генерируется не текст, а код. А далее уже всё это собирается крестовый компилятором, который опять же не претерпел изменений с дошаблонных времён.
При этом ничего не мешает эмулировать логику си своей логикой. Вот допустим, как я уже выше писал, в си на уровне языка не существует функций. Просто кусок данных, который компилятор скомпилировал и создал объект — дал ему имя. Линкер его прилинковал. На уровне кода это тупо указатель/ссылка.
С++ экпортировал эту логику. Добавил к ней ту же перегрузку, но опять же в С++ функции на уровне языка не появились — опять же только указатели. Опять же те же самые отдельные куски данных. Что мешало в С++ вывести функции на уровень языка? Они итак уже стали несовместимы с сишными на уровне бинаря. Правильно — ничего. Можно было бы на этом реализовать сишное поведение и прочее? можно. Почему это не было сделано? Правильно, ибо С++ это си.
И всё просто в С++ перегруженная функция была бы одной функцией, а не множеством. Её можно было бы спокойно передать как некую общую сущность. Это собственно крестовики и кастылили создавая объект и реализуя перегрузку через перегрузку оператора (). Ибо они понимали, что этот функтор — это и есть функция уровня языка, а не убогий сишный кастыль из 60-х.
И так со всем.
Эм, что? Вы макросы с шаблонами точно не путаете?
То. Хотя о чём это я. Экперты тутошние даже не знают что такое шаблоны.
Т.е. если в сишке бахнули поверх языка препроцессор, то шаблоны есть ни что иное как тот же самый импрувнутый препроцессор. Только уже генерируется не текст, а код.
Это что? Хотя о чём это я. Это ведь не ответы — это просто невежество.
Ладно — буду срывать покровы. Шаблоны работают точно так как препроцессор — занимаются тупой подстановкой значений. Только подставляют они сущности уровня кода( о чём я писал выше) на уровне кода есть значения и типы. Ну и целом они более мощны, ибо созданы были не в 60-х( в том же препроцесоре запрещена рекурсия) поэтому и тормозят так безбожно.
Т.е. это такой же отдельный от языка уровень. Но который уже более стильный и работает не с текстом. В остальном проблемы всё те же и использование то же.
А значит ли это, что си — это ассемблер?
Эти убогие попытки. Нечего сказать — скажи херню.
А какую логику из ассемблера экспортирует си на уровень языка? Поподробнее.
Вы можете только дёргать куски моих фраз, врать( выкатывать какие-то подробности в ответ мне, при этом никакого следствия из этого не выводя делая вид, что это уже и есть ответ и он как-то опровергает мои слова. Приписывать мне всё что угодно на основании интерпретации моей цитаты «как я захочу» и прочие инсинуации).
Как минимум, есть частичные специализации
И что же из этого следует? Правильно — ничего. Это не тупая подстановка значений?
а значит, есть паттерн-матчинг
Нету. На уровне шаблонов есть только генерация тонны типов и в этих тоннах говна компилятор уже копается — опять же тупым перебором с приоритетами.
Да и опять же — к чему эту потуги? Это что-ли что-то меняет? Либо делает мои слова неверными?
условные операторы
Нету. Можете мне попытаться его показать, только не накостыленный, а именно оператор.
«Условные операторы» есть и в препроцессоре, но опять из этого ничего не следует, ибо это не меняет природы работы макросов.
и полная Тьюринг-полнота.
Как и в брайнфаке.
На шаблонах это всё немножечко сложнее.
Это не сложнее — это нету. Опять же — накостылить ифы можно на брайнфаке, только из этого не следует то, что они есть в языке.
Сделайте мне
Опять пошел какой-то байт на трату моего времени и заведомо ущербанские предъявы.
Как им образом из:
В остальном проблемы всё те же и использование то же.
Следует «я бахну на макросах то же самое, что и на шаблонах». Правильно — никаким. Просто обосрамс и начало пасты ахинее.
Кстати, какое отношение к шаблонам имеет сишный тайпдеф? И прочие сишные и крестовые конструкции? Именно этим и отличается шаблоны и макросы, что макросы работают с текстом, а текст не имеет никакой логики( она минимальна). А шаблоны работают с языковыми конструкциями( функциями, классиками, переменными) и всё это обладает логикой, в отличии от текста, и именно благодаря этому шаблоны и кажутся балаболам мощнее макросов. Но забери у них всё это — останется пустота.
это что-то новенькое!
Массивы C++ — std::array.
Это не уровень языка. Это не более чем поле с сишным массивом.
Желаю удачи с неявными кастами из\в void*.
В крестах есть какие-то проблемы с неявным кастом в воид? Вот это новости.
Это косметическое отличие. Если уж говорить об изменении кастов, то говорить надо об уменьшении силы сишного каста в крестах, а вернее наделение его логикой крестового каста. Но опять же это косметика, ибо ничего на уровне языка не поменялось.
С++ «обратно совместимый» не потому, что он эмулирует поведение си — он и есть си. Изначально существовал как надстройка над си, да и сейчас существует. Никаких фундаментальных даже расширений сишной логики уровня языка нету, я уж не говорю о своей.
Именно из-за того, что С++ есть си в нём и есть та тонна проблем о которой я писал ниже.
А что произойдёт, если вы аллоцируете массив из N объектов, и какой-то из конструкторов этих объектов бросит исключение?
Конструкторы не имеют никакого отношения к аллокации. Опять же отвечающий мне путает operator new и new, но такое бывает.
Из этого следует, что любую программу на C++ можно собрать компилятором C, а это, очевидно, не так.
Не следует. На основании чего это следует?
Из этого следует лишь то, что всё то, что есть в С++ и си — это одно и то же — это си.
Но опять же всё это не важно, ибо вам ответ не более чем попытка юлить. Вам было сказано это в контексте:
С++ «обратно совместимый» не потому, что он эмулирует поведение си — он и есть си.
Естественно из этого понимается то, что говорится только о частях эквивалентных( в вашем понимании совместимых) с си.
В коде new используется куда чаще, чем operator new, поэтому обсуждать последний, особенно для доказательства, что в C++ ничего принципиально нового нет, одни прокси к malloc, не имеет особого смысла.
Слив. Я уже опустил слив с массивами из С++, которых не существует. И перлами вида «ссылка из С++ есть указатель из си».
выделение памяти C (malloc/free) и выделение памяти C++ (new/delete)
Чтобы оратор опять не слился на свои интерпретацию понятия «выделение памяти» — разберём его цитатку.
Он назвал «выделением памяти» маллок. Т.е. оратор использовал понятие «выделение памяти» как выделение памяти в общепринятом значении.
А далее оратор называет аллокатором в С++ new, что является неправдой. Ибо new нихрена не аллокатор, а создатель объектов.
И тут оратор загнал себя в угол, ибо он говорил не про объекты, а про память. А теперь же он слился на объекты.
Из утверждения «эта программа написана на языке, который и есть си» не следует, что её можно собрать компилятором си? Окей, а что тогда значит, что программа написана на языке, который и есть си?
Очередной слив. Полный игнор уличения оратора в подлоге. Ни о какой программе и ни о каком языке речь не шла. Речь шла о:
С++ «обратно совместимый» не потому, что он эмулирует поведение си — он и есть си. Изначально существовал как надстройка над си, да и сейчас существует.
В данном случае( и это разобрано выше) говорится именно о части С++, который типа совместим с си, а при этом на самом деле и является си.
А далее если учитывать то( это я уже выше/другх постах разбирал) то, что в плане языка С++ состоит из си с прикрученными классами( исключениями и rtti, но опять же это в больше степени левый рантайм, а не уровень языка), то С++ ни что иное как си. Но это уже к делу не относится — это про следующие предложение которые вы не пастили. Хотя вы и не пастили и первое, иначе без вранья и передёргивания отвечать было бы нечего.
Изучите понятие надмножества и используйте его, пожалуйста, а то получаются такие вот непонятки.
Очередные кидания левыми понятиями. Если это надмножество, то о какой такой «обратной совместимости» вы говорили выше?
А при этом если надмножество С++ является в плане языка состоящим на 95% множества Си, то является ли С++ каким-то самостоятельным множеством? Да и с любыми раскладами — является ли С++ самостоятельным множеством?
При этом я говорю не о синтаксисе, либо семантики каких-то общих для языка конструкций. Я говорю о полной пасте си.
Окей, тогда мой ответ (не ораторский): в C++ есть не только operator new.
Из этого ничего не следует.
Совместимая с С часть совместима с С, ломающие новости.
Опять какие-то убогие попытки написать херню. Говорилось не о совместимости, а о причинах этой совместимости. Хотя опять же С++ не совместим с си.
То есть, программу на С++ можно собрать компилятором С? Иначе я не понимаю смысла этого утверждения.
Очередная херня. Дело не в том, что кто-то чего не понимает — дело в том, что кому-то сказать нечего и начинаются инсинуации.
Смысл уже давно был определён. С++ не является языком совместимым с си — он является си в той части в которой он совместим с ним. Ибо по определению понятие «совместимости» не подразумевает того, что совместимое является тем же самым, что и то с чем собственно оно и совместимо.
Об обратной совместимости пересечения, очевидно. Вы вообще понимаете, что такое «обратная совместимость»?
Опять какой-то невнятный высер. Что из этой потуги должно следовать?
Откуда тут число 95% взялось? Почему не 99%? Не 42%? Не 0.01%?
Очередная потуга ещё более убогая чем предыдущая. Был задан конкретный вопрос с конкретными условиями. Какой там число не является принципиальным — нужен чёткий ответ да или нет.
Дайте определение «самостоятельного множества» сначала, чтобы синхронизировать терминологию.
Вот мы видим всю убогость балаболистики. Ведь ниже сказано «Да и с любыми раскладами», т.е. заранее дан ответ на потуги про «а если не 95%». Но зачем отвечать нормально? Правильно — херня наше всё.
Вы назвали язык множеством? вы. Я приписал к нему свойство которое есть и может быть у языка. Что вам не ясно?
Самостоятельное множество является оным тогда, когда его определяющая, либо основная часть является им, а него экспортируется из подмножеств. Т.е. когда его элементы могут существовать сами по себе. Т.е. когда эти элементы являются элементами, а не свойствами/элементами элементов.
Хорошо — оставим это. Определимся с множеством. Что есть «множество языка»? Из чего оно состоит?
Из этого следует, как минимум, что конструкция с new интереснее, чем прокси к маллоку.
Очередная потуга. Хотя что с вами балаболами спорить. Выше вами же было определено, что:
выделение памяти C (malloc/free) и выделение памяти C++ (new/delete)
Т.е. (new/delete) — «есть выделение памяти C++ ». Вам сказали, что это не так. В данном случае вы сравнивали аллокаторы и явно это указали. Все потуги не имеют смысла.
Но при этом является Си. Ясно.
А С++14 не совместим с С++11 — является ли он С++? А является ли CL лиспом?
В данном случае балабол пытается как и любой балабол подменять понятия. Как бэ это объяснить попроще, чтобы домохозяйке было понятно.
Вот у нас есть айфончик. У айфанчика есть коробка. Есть айфончик в чехольчике. Можно ли на основании того, что айчинчик в чехольчике не влезает в коробку сделать вывод, что айфончик в чехольчике не является айфончиком? Ведь он с коробкой не совместим, а значит имеют другую форму и габариты. Т.е. его представлению в пространстве добавлены новые свойства.
С логикой домохозяйки айфончик в чехольчике айфончиком не является. При этом явно и понятно, что айфончик не совместим с чехольчиком на уровне коробки и наоборот. Следует ли из этого то, что айфончик в чехольчике не айфончик?
Если же пойдём дальше и будем учитывать только форму( ну с логикой домохозяйки иного и не дано), но тут у нас уже возникает вопрос — что определяет форму айфончика в чехольчике? Чехольчик или айфончик? Уж явно не чехольчик, но так же явно и не сам айфончик в полной мере. Хотя он без чехольчика существует, а чихольчик без него нет — это уже определяет то, что является из них основополагающим елементом.
Далее домохозяйка пытается съехать на то. Я ей ответил, что коробка для айфончика с чехольчиком так же не совместима с айфончиком, как коробка для айфончика с айфончиком в чехольчике. Это конечно логика уровня школы, но куда уж там.
При этом тут ясно и понятно вся бессмысленность рассуждений домохозяйки о том, что тут что-то неверно, либо аллогично. Просто надо опуститься на уровень понятий доступных вам, если вы не можете рассуждать на уровне понятий вам предоставленных контекстом статьи, моего комментария и прочего.
Ну раз число не является принципиальным, я его заменю и на вопрос «А при этом если надмножество С++ является в плане языка состоящим на 0.01% множества Си, то является ли С++ каким-то самостоятельным множеством?» со спокойной совестью дам ответ «нет».
Слив засчитан.
Для любого множества элементы его подмножеств принадлежат этому множеству. Ваше определение неконструктивно.
Опять же, если ваш уровень развития не позволяет вам говорить ничем иным, кроме заклинаний и воспринимать какие-то более сложные объекты — будем на простых.
На уровне доступном вам. Вот у вас, в детском садике, есть шарики на ниточке в руке у васи. Т.е. элемент есть шарик — их 3 — это множество шариков.
Мы рисуем но одном шарике кракозябру. Поменялось ли множеством шариков? Нет. В данном случае поменялось свойство конкретного элемента.
И в чём заключается ваша попытка подлога — вы подменяете заранее определённое понятие «элемент множества это» на на «элемент множества это то, что хочу я». В данном случае множество шариков как объектов, и множества свойств этих объектов.
И получается то, что изменение свойства чего-то не является определяющем для определения объекта с изменённым свойством как нового объекта, ибо эти свойства не являются определяющими.
И вам привили пример. Есть функции. Функции это объект — конструкция языка. У этой функции есть неопределяющие свойства — т.е. отсутвие/наличие какого-то из этих свойств не делают функцию другим объектом.
То же самое, допустим, и с языком. Новая фишка в С++ не делает новые С++ новым объектов как язык, ибо фишка не является определяющим для определения чего-то как «новый язык».
Точно так же, как редакция какой-то книги не определяет содержание книги как «новое», ибо не изменения не являются определяющими.
Из допустимых программ, очевидно.
Это не очевидно — это бред балаболистики. Язык не определяется какими-то там нагромождениями его конструкций, ибо они бесконечны и сравнение их, как и определение и выделение не имеют смысла.
Домохозяйки такие домохозяйки. Наверное сортир определяется так же множеством возможных сортиров, а не конкретными критериями, которые определяют его как сортир. Хотя балаболистика + домохозяйка — ничего нового в результате.
Язык определяется по набору конкретных лексем и правилам работы с ними. Никаким образом язык не определяется множеством «текстов», ибо определение не имеет смысла.
Точно так же как ЯП определяется набором каких-то языковых конструкций и общей логикой — моделью памяти, сборки и прочее.
Фраза, которую вы сказали: «C++ является C» чисто математически должна означать «Код на C++ должен быть успешно скомпилирован компилятором C».
То, что вы пытались донести до аудитории, повидимому, должно было звучать наоборот: «C — это часть C++». Но с этим, вроде, тут никто и не спорил.
Когда речь заходит об обратной совместимости, предлагаю вам простой эксперимент.
Напишите программу вида:
void foo() {
}
Укажите расширение файла ".c" и скомпилируйте ее в DLL (или shared object). Затем создайте другую программу вида
extern void foo();
int main() {
foo();
}
Тоже укажите ".c". Скомпилируйте ее и слинкуйте с первой динамически.
Вы получите успешно работающую ничегонеделающую программу, которая, тем не менее, вызывает успешно работающую ничегонеделающую библиотеку.
А теперь, опираясь на ваше утверждение об обратной совместимости, давайте попытаемся переименовать оба файла в ".cpp" и, соответственно, воспользоваться компилятором C++, вместо C.
Если вы попробуете это сделать, вы обнаружете, что процедура линковки не пройдет успешно, так как компилятор C++ не найдет в вашей библиотеке функцию «foo()». Если вы запустите nm, вы заметите, что функция называется иначе.
Это называется name mangling.
Для того, чтобы включить линковочную совместимость с Си, существует, какмы все знаем, директива
extern "C"
. Которая, в свою очередь, непонятна компилятору C — если вы напишете ее в файле ".c", он его не скомпилирует.Таким образом, мы обнаруживаем, что данная — тривиальная — программа не может быть написана совместимым способом на двух языках одновременно.
И мы вынуждены иcпользовать макроопределения типа __cplusplus. Но вы же не считаете использование макросов способом достижения совместимости, так ведь? Потому что если считать, то можно сделать Си совместимым хоть с Фортраном, хоть с Ассемблером.
Таким образом теорема об отсутствии обратной совместимости между C++ и C доказана предъявлением контрпримера.
Удовлетворены?
То, что вы пытались донести до аудитории, повидимому, должно было звучать наоборот: «C — это часть C++». Но с этим, вроде, тут никто и не спорил.
И это тоже неверно.
gross@unterwelt [10:29:58] [~]
-> % clang -std=c++11 -o test test.cpp
test.cpp:4:8: error: cannot initialize a variable of type 'int *' with an rvalue of type 'void *'
int *a = malloc(sizeof(int));
^ ~~~~~~~~~~~~~~~~~~~
1 error generated.
gross@unterwelt [10:29:59] [~]
-> % mv test.c{pp,}
gross@unterwelt [10:30:22] [~]
-> % clang -std=c99 -o test test.c
gross@unterwelt [10:30:32] [~]
-> %
Из этого следует, что любую программу на C++ можно собрать компилятором C, а это, очевидно, не так
Если С++ — это «С плюс надмножество», то любую программу на С можно собрать компилятором С++
При этом далее пошел не только слив, но и враньё. А вернее паста выдранного из контекста куска, хотя на что вы, балаболки, ещё способны.
«я не понимаю» — это не ответ. Вы можете не понимать только потому, что в моих рассуждениях есть какие-то дыры, либо потому, что вы дурак. Если никаких дыр и фактов слабости суждений у вас — вы дурак. А это ваша проблема.
В целом ваши потуги предсказуемы. Тот, кто совсем лсный балабол обвиняет меня в том, что крестов я не знаю. Кто-то более-менее вменяемый понимает о чём я пишу, а так же то, что написать это без знания этих самых крестов нереально. Но опять же тактика перехода на личности не меняется. Потуги строятся на «оппонент дурак», игнорирования неудобных вопросов да и вообще всех вопросов. Ну и конечно же враньё, подлоги, чернуха уровня «расскажу какой он дурак все округе» ну и в конечном итоге всё сводится «а чего добился ты?», либо «все за меня/ авторитеты за меня» — т.е. перекладывание ответственности во внешний мир.
Что мы собственно и видим. Ничего не меняется — каждый балабол уверен в том, что можно нести любую херню и он прав по факту.
Очевидно, человек стесняется сформулировать эту точку зрения открытым текстом и, поэтому, пытается ее облечь в язык математических понятий, что, впрочем, ему не всегда удается.
Не подведет, если собирать программу целиком, а не отдельные модули
Строго говоря, линковка — это не компиляция, а отдельный процесс. Таким образом, на уровне компиляции ваш пример некорректен
Почему? Можно скомпилировать код разными компиляторами с разных языков (или разными версиями одного и того же компилятора) и скомпоновать в один исполняемый модуль. А некоторые лицензии позволят не распространять ваше ПО, не раскрывая его кодов, но поставляя объектники, которые можно будет скомпоновать с другими обновившимися частями. Не вижу никакого буквоедства.
2. Какое перечисленные примеры имеют отношение к совместимости между C и C++, обсуждаемой в контексте данной дискуссии?
Статические массивы есть. С сохранением типа при передаче по ссылке.
>он и есть си
Что за бред? Вы вообще писали на плюсах что-то, кроме пары лабораторных работ?
Статические массивы есть. С сохранением типа при передаче по ссылке.
Нету. И быть не может.
Что за бред? Вы вообще писали на плюсах что-то, кроме пары лабораторных работ?
Опять же тактика отвечающих не меняется. Выдираем из контекста, врём и обвиняем. Зачем уровень своих познаний( а вернее 3-х лабораторных работ) экстраполировать на меня?
Ответ на это враньё есть выше.
Ну что за убогое убожество населяет эту борду. Балабола уличили в том, что он выдрал из контекста фразу про «он и есть си». А уже после этого балабол рассуждает а каких-то лабораторных и делает вид, что «выдирание из контекста» было про какие лабы.
Невероятно.
А стоит лишь полезть в детали, как выясняется, что зачастую семантика этих внешне сходных конструкций — различается между С и С++. Но даже если бы все фичи из вашего списка вели себя идентично в обоих языках, это все равно не свидетельствовало бы о полной обратной совместимости. Это будет примерно как попытка доказать математическую теорему путем перечисления примеров, на которых она справедлива.
А уж то, что большинство упоминаемых вами свойств (`std::vector`, `std::string`, `C-string`, `printf`, `std::iostream`, `malloc`) вообще реализованны *на уровне библиотеки*, делают их вообще неуместными в рамках данного вопроса. Никто вам не запрещает реализовать С-style строки или `malloc` в Паскале. Это, однако, не будет свидетельством какой-то «обратной совместимости» Паскаля и С.
Косноязычие не позволяет понять, что именно имеется в виду.
Я так понял, что автора напрягает отсутствие неявного преобразования.
Нет.
Да. С++ не более чем надстройка над си. Ничего своего там на уровне языка( а не сахара) нет. Вся логика работы с функциями экспортирована из си и по этой причине перегрузка функций выглядит как кастыль и работает как кастыль. Попробуйте сделать какой-нибудь std::invoke на перегруженную функцию — не получится, а проблема одна — си. Ибо на уровне языка не существует никакой перегрузки — это убогий кастыль с именами. На уровне языка даже функций нет. Только указатели, хотя тип-функция и есть, но это тупой ссылка.
И так везде. Всё что должно работать и не работает — это наследие си. Нету constexpr памяти? Си. С++ ничего не знает об объектах и памяти — этого не существует на уровне языка( да то же rtti накостылено на именах, отсюда и рефлекшена нет, хотя с чего ему не быть в статическом языке? А правильно — он нихрена не статический.). Строковые литера ущербны? Си. Опять же в си это просто глобалы с законстыленной логикой инициализации.
Различия С и С++ — огромны и фундаментальны.
Их нет. Это не отличия — это просто обвес. Нельзя сравнивать С++ с тем, аналогов чего нет в си. Если сравнивать, то имеет сравнивать именно основу и изменение в основе, которая и есть язык, а сахар и левая логика — это не язык.
Если мы сравниваем Си(чай) и С++(чай с сахаром и ложкой классиков), то мы не можем сравнивать сахар в них, либо классики, ибо их нет в первом случае. Мы сравниваем только чай. Ибо и в первом и во втором напитке основой является чай, а не сахар. И именно этот чай из С++ есть ни что иное как чай си. Ни какой-то другой чай, а именно он. И опять же от добавления в него чего-то ничего не поменяется, ибо основа есть основа.
С — lvalue-discarding language, C++ — lvalue-preserving language. Уже этого достаточно для того, чтобы заявлять, что любые сходства между этими языками — не глубже уровня сходного синтаксиса.
Это пустые рассуждения, когда сравнивается левая логика. На уровне железяки есть только копирование. И ничего иного. С++( а вернее раишные куллстори) изначально построен на подмене понятий — копирование( присваивание) объектов не есть копирование их данных, а есть отдельная вызываемая логика. Именно из этого идут все различия. На уровне же языка ничего не меняется — логика остаётся сишной( логика по умолчанию).
Т.е. в крестах просто добавили возможность менять эту логику( оставив сишное поведение — поведением по умолчанию). Из этого ничего не следует — это не уровень языка. Далее вернули сишную логику копирования и назвали её «перемещением», что на самом деле и есть копирование.
А далее все эти рассуждения про типы ссылок — это опять же не что иное как логика вызова( или не вызова) конкретных методов( т.е. левой логики при копировании объектов).
Уже давно было объяснено, что inline больше не имеет отношения к оптимизации.
Кем и почему?
Этот спецификатор влияет лишь на то, как определение функции взаимодействует с One Definition Rule
Бессмысленной правило вызванное наследием Си и 60-х годов. Но мы его не обсуждаем.
Начнём с того, что инлайн из си обладает таким же поведением, только причина этому в том, что функции не является объектом и на уровне линковки её просто не существует. В крестах добавили этому костыльную логику вида «первое определение и есть объект». При этом можно спокойно определить 2разные функции и получить интересные эффекты с тем, что в одном случае работает одна, а в другом другая.
Это чисто поведение экстерн, только вот экстер надо где-то всегда объявлять и с этим есть проблемы. В крестах и си экстерн определение не имеет семантики и это как раз таки и есть то на что надо было вещать логику работы текущего инлайна из крестов.
Но опять же это лишь дополнительная логика инлайна для глобалов и само «встраивание» никуда не делось.
, и не более ни на что.
А не для глобалов?
В С++17 появятся inline-переменные, где новая роль inline сияет во всей красе.
Ну на самом деле это логика «определи, либо игнорируй если определено» и то, что её повесили на инлайн — из этого ничего не следует. Да и аллогично это.
С этой точки зрения все транслируемые языки — не более, чем надстройка.
Надстройка над чем? Причём тут транслируемые языки?
Есть что ответить — отвечайте. Нечего — не отвечайте. Всё просто.
Если же мы расширяем термин «надстройка» до уровня «может иметь одинаковое представление на нижнем уровне», то под надстройку Си попадает множество языков, к Си, в общем, отношения не имеющих. В том числе ВСЕ языки, которые могут быть интерпретированы в Си или которые выполняются в виртуальной среде, написанной на Си. В том числе и Java, и Python, и все ЯП, прогоняемые через LLVM. А это очень много.
Далее, вы смешиваете язык, его реализацию, и отображение на машинные коды, то есть скомпилированное приложение. Я лично не встречал указания по именованию скомпилированных методов в стандарте. Так что то, что получится в итоге и какая дополнительная информация будет приложена к классу — зависит только от компилятора. Более того, вы периодически выкрикиваете «в памяти нет того-то, в памяти нет сего-то». Действительно, нет. Так что ваш трёп вообще не имеет смысла, в памяти кроме локальных ловушек для электронов вообще ничего нет, ни байт, ни бит. А вот в структуре и синтаксисе языков программирования они есть. Есть там и типы, и методы, и enum'ы. Мне абсолютно насрать, как будут они отображены на машинный язык, которых есть многие сотни, мне важно, что вот тут, сверху, у меня есть класс с тремя виртуальными методами. И вот тут, сверху, все ваши memset'ы посасывают, не будучи способными корректно скопировать виртуальные указатели.
Вот тут, сверху, с++ и с не имеют ничего общего, кроме базового форматирования. А что творится двумя этажами ниже, меня интересует при оптимизации кода, то есть «не сегодня» ©.
Что касается перегрузок, если бы вы были правы, то invoke бы сработал. Это же очевидно, он подставляет типы в шаблон, проходится поиском по имеющимся методам и выбирает из них первый подходящий. К сожалению или к счастью, он так не работает. Шаблоны — не макросы, они о другом. Кстати говоря, почему срабатывают перегрузки operator()?
http://coliru.stacked-crooked.com/a/b6b5f4ef32528ace
Конечно, порой не хватает более мощного инструмента для мета-программирования, но тут уж что есть. Я бы его, в любом случае, не стал сравнивать с макрогенератором.
Зайдём с формальной точки зрения. Надстройка — это то, что может быть выражено через базовый функционал. С какой стороны не зайди, хоть бытовой, хоть судостроительной, хоть марксистско-идеалистической, надстройка является следствием базиса, выражается через базис и выполняет функцию оптимизации и повышения удобства работы этого самого базиса. Вы можете выразить плюсовые шаблоны через макросы? Нет? А на плюсах писать, не трогая <cstd*>? Да? Ну, значит, не надстройка, а самостоятельная сущность. А то же самое Qt или boost — надстройки, так как они целиком реализуются из чистого с++.
Мне уже лень разбирать ваши потуги уровня первого класса. Это настолько фееричные высеры. Какая оптимизация? какой ещё нахрен базис. Настройка это то, что имеет основу и не может существовать как самостоятельный объект.
Является ли анальный зонд подключаемый к айфону надстройкой? По логике( вернее её отсутствию) тутошних экспертов нет. Но это ладно.
А на плюсах писать, не трогая <cstd*>? Да?
Нельзя. cstd не является языком ни в коей мере — это кусок лишь сишного рантайма. Да и не существует никаких реализаций крестового рантайма не основанного на сишном.
Очередная подмена понятий от балаболов. Язык состоит не из рантайма — язык состоит из языка, а рантайм лишь код на этом языке который входит в поставку языка.
А далее мы задаём правильный вопрос — если из С++ выпилить си, то что останется от С++? Правильно — ничего. Даже синтаксиса не останется, но опять же к синтаксису я не придираюсь.
Если же мы расширяем термин «надстройка» до уровня «может иметь одинаковое представление на нижнем уровне»
Опять какой-то убогий высер. С++ является си не на уровне какого-то там конечного представления — он является им на уровне начального преставления.
Для ламерков и балаболов это слишком сложно. Банальный пример с теми же функциями — std::decay -это что? Правильно типичный пример экспортированной из си логики.
Далее, вы смешиваете язык, его реализацию, и отображение на машинные коды, то есть скомпилированное приложение. Я лично не встречал указания по именованию скомпилированных методов в стандарте.
Именование тут не причём — очередной убогий высер. Дело в том, что по определению перегруженные функции не являются одной функций, а являются разными функциями — почему? Правильно — по той причине, что в си нету перегрузки функций.
Я лично не встречал указания по именованию скомпилированных методов в стандарте.
Причём тут методы? Если говорилось о функциях? Ну а далее всё просто — перегруженные методы являются одним методом? Либо разными?
олее того, вы периодически выкрикиваете «в памяти нет того-то, в памяти нет сего-то». Действительно, нет. Так что ваш трёп вообще не имеет смысла, в памяти кроме локальных ловушек для электронов вообще ничего нет, ни байт, ни бит.
Очередной убогий высер. Про какие-то там электроны.
Это высер не имеет смыслу уже потому, что на уровне программном существует только программный мир и рассуждения о електронах смысла не имеют.
Концепция памяти на уровне языка описана.
А вот в структуре и синтаксисе языков программирования они есть. Есть там и типы, и методы, и enum'ы.
С т.з. памяти( и это описано на уровня языка) тип имеет только одно свойства — sizeof. Никаких иных свойств у типа с т.з. памяти нет и быть не может.
Тип это не про память — тип это про интерпретацию данных. Интерпретация данные к памяти отношения не имеет — это исполняемая логика.
Мне абсолютно насрать, как будут они отображены на машинный язык, которых есть многие сотни, мне важно, что вот тут, сверху, у меня есть класс с тремя виртуальными методами.
Очередной убогий высер. Никто ни про какие машинные языки не говорил. Говорилось про память. Нигде на уровне языка не существует никакого типа у «блока памяти» чем-то распределённого, а в том контексте аллокатором динамическим. Это определено на уровне языка. Существуют типы памяти, аля динамическая, статическая, локальная и прочее, но это к делу отношения не имеет. Она ничем друг от друга не отличается — это свой понятия моеделей менеджмента этой памятью на уровне языка, либо за его уровнем.
Причины сливая я уже описал. Классы как сущности совмещающие логику исполнения с данными являются любимой темой слива лсных балаболок. Инвариант валидного состояния конструкции поддерживается рантам логикой. К памяти это отношение не имеет. Уровень памяти как копировался мемкопи так и копируется.
Что касается перегрузок, если бы вы были правы, то invoke бы сработал. Это же очевидно, он подставляет типы в шаблон, проходится поиском по имеющимся методам и выбирает из них первый подходящий.
Что? Какая-то неведомая херня.
К сожалению или к счастью, он так не работает.
О боже, днище не понимает почему не работает инвок. А я поясню. Он не работает по той причине, что невозможно в функцию передать функцию. Т.е. функции на уровне С++, а вернее на уровне си представляют из себя уникальные объекты доступные по ссылке(имени)/указателю. На уровне си никакой перегрузки функций нет, а значит все работает нормально.
В крестах же перегрузка функций есть, но штука в том, что по банальной логики вменяемости перегруженная функция должна являться один и тем же объектом. И ссылка на эту функцию должна быть ссылкой на всё множество пергруженных функций, которая и выбирается уже исходя из переданных аргументов.
Но т.к. такого поведения нет и инвон растрывается тупо в указатель на функцию, а указатель не может ссылка на не конкретную функцию, то инвок работать не может.
Кстати говоря, почему срабатывают перегрузки operator()?
Пацан реально не понимает, либо ослит? Я уже писал про оператор().
Функтор есть ни что иное как правильное представлении перегруженной функции на уровне языка. Но является один объектом вместе независимо от кол-во перегрузок у оператора. И естественно тут эксперт передаёт этот объект.
Но функтор есть ни что как кастыль. Как и все С++.
Конечно, порой не хватает более мощного инструмента для мета-программирования, но тут уж что есть. Я бы его, в любом случае, не стал сравнивать с макрогенератором.
Шаблоны никакущий инструмент для метапрограммирования — его там нет.
Вот так и живём, что #define invoke(f, args...) f(args) может больше, чем мощные шаблоны.
В целом я не понимаю вас. Вы либо меня тралите, либо не понимаете того что такое шаблоны и почему они мощнее макросов. Одновременно с тем почему они и менее мощные.
Ещё раз — шаблоны это такой же макрогенератор, только вместо аргументов-«строк» там значения и типы. Всё. Вся шаблонная магия не имеет никакого отношения к шаблонам — эта магия мощи сишного синтаксиса и системы типов.
Если будет не лень мне — я сделаю отдельный разбор. Вдруг вы рально не понимаете.
Я думал с вами ещё посраться, сказать, что Си без std* существовать не может, а c++ — запросто; что почти во всех языках перегруженные методы\функции являются разными синтаксическими единицами с разными внутренними именами, о чём можно узнать, декомпилировав те же классы шарпов и жавы; что перепрыгивание между функциями и указателями в обсирании шаблонов не имеет смысла, так как шаблоны не работают с адресами вообще, а все проблемы кастов сводятся именно к алгоритму подстановки и перебора типов, но потом…
> Нигде на уровне языка не существует никакого типа у «блока памяти» чем-то распределённого, а в том контексте аллокатором динамическим. Это определено на уровне языка.
… потом я понял, что это бесполезно. Я не могу сраться с тем, что само себя не понимает. Хотя было достаточно интересно прочитать такое полотно от человека, которому «делать больше нечего, кроме как кому-то что-то доказывать».
Можешь засчитывать это за слив, только запятые в процессе не теряй — и так речь сумбурная, хрен поймёшь.
Почему претензия только к отсутствию PCRE? Я вообще хотел-бы что-бы Extended POSIX Regexp поддерживался.
Вообще статья ни о чём. Можно подумать, те кто пишут на любимом языке, не знают его проблем.
Эх, увидев оглавление, я сначала подумал, что это подборка более развёрнутых статей на соответствующие темы. А тут как-то по верхам и местами даже мимо кассы.
• JavaScript унаследовал непонятный и проблемный синтаксис регулярных выражений у Perl.Хотелось бы поподробнее, что в нем непонятного и особенно что в нем проблемного
• Регулярное выражение (a|[^d]) преобразует StackOverflowException в длинные строки.Искренне не понял о чем это
(a|[^d]) regex throws StackOverflowException on long strings
Но автор перевода не очень шарит и/или не очень напрягался и теперь мы лицезреем такие жемчужины по всей статье.
Очевидно, что автоматически понять, является ли программа безопасной и корректной, в общем случае невозможно. Safe-подмножество Rust разрешает лишь подмножество безопасных программ. Поэтому глупо жаловаться, что borrow checker «отвергает безопасный код». Конечно, хочется, чтобы язык позволял более широкий спектр безопасных программ, но никогда не будет такого языка, который отвергает весь опасный код и принимает весь безопасный.
> В конце концов, «небезопасный» блок не говорит, что содержание блока вызовет неопределённое поведение
Естественно. Safe Rust в идеале гарантирует отсутствие неопределенного поведения, но обратное неверно. Если бы процитированное утверждение было неверно, то это была бы очень комичная ситуация — специальное ключевое слово, чтобы писать только некорректный код.
> это означает, что содержание небезопасного блока было ошибочно отклонено компилятором.
За исключением багов компилятора, нельзя здесь говорить об ошибочности. Ограничения safe Rust задокументированы. Опять же, никто не обещал, что он примет любую программу, которую можно считать корректной.
> borrowck, всё же, имеется, даже когда вы находитесь внутри unsafe {} блока или функции
Но там с ним можно легко расправиться, если использовать указатели вместо ссылок.
> чтобы сотворить, действительно, волшебство, необходимо дать вызов, содержащий некоторые многословные имена вроде sliceable.unsafe_get(index).
В стандартной библиотеке нет unsafe_get. Если имеется в виду get_unchecked, то он используется для получения элемента массива без проверок на границы индексов и к borrow checker не имеет отношения.
> Никто не знает, какие правила определяют опасность.
> Это означает, что содержимое небезопасного блока является трудным для чтения, что оно по определению является слишком сложным, чтобы быть очевидно правильным, что оно нечётко задано и должно быть написано на коде низшего уровня.
Писать unsafe-код корректно в Rust действительно сложно. В Rustonomicon об этом хорошо написано.
Зато известно, какие правила определяют «безопасность» в терминах Rust. Эти правила компилятор проверяет и не даст вам ошибиться. Так что писать на безопасном подмножестве можно вполне спокойно.
> У Rust есть исключения. Он называет их тревожными и редко использует их, но у него они есть, и ваш небезопасный код должен быть транзакционным в отношении безопасности памяти. До сих пор они имели примерно такой же успех, последовательно соблюдая это, какой имели разработчики в C++ (за исключением тех разработчиков в C++, которые запрещают исключения, как, например, Google).
Непонятно, в чем проблема. На C++ можно писать код, безопасный по отношению к исключениям, и в Rust ничуть не меньше средств для этого.
> Таким образом, «безопасность» Rust позволяет делать существенно меньше ошибок в чрезвычайно простых кодах, но не помогает в сколько-нибудь сложных.
Rust не защитит от логических ошибок, которые свойственны большим программам, но по крайней мере, у вас не будет в них сегфолтов и конкурентного доступа к непотокобезопасным данным. Это очень помогает на практике.
> Точки с запятой и неприятный синтаксис :: получены в наследство от С++. Также унаследован ещё более безобразный шаблонный/универсальный синтаксис.
Дело вкуса.
> Обе эти функции осуществляют проверку и не возвращают предупреждений, но делают весьма различающиеся операции.
Эти функции делают одно и то же, только одна возвращает результат последнего выражения, а другая нет. Для тех, кто знаком с синтаксисом, нет ничего неочевидного. Если бы вы так попытались сделать с типом Result, то компилятор выдал бы вам предупреждение, не позволив просто так забыть обработать ошибку.
> Чрезмерно кратко поименованные типы и ключевые слова, которые не передают их назначение, как, например, impl и ().
Плохие примеры. «impl» — сокращение от «implement», и код вида «impl MyStruct» или «impl MyTrait for MyStruct» читаются очевидным образом. () — пустой кортеж, частный случай синтаксиса (T1, T2, ...). В чем тут проблема, непонятно. Я бы лучше поругался на ключевое слово type, которое мешает называть этим словом переменные и функции.
> mut означает исключительный, а не изменчивый (mutable).
Нет, «mut» означает «изменяемый». Например, «let mut x = 1;» — декларация изменяемой переменной (без mut была бы константная). В ссылках "&mut x" также означает «изменяемый», а исключительность уже следует из правил Rust.
> &Mutex означает изменчивый (mutable)
Mutex и RefCell являются в некотором роде исключениями. Использование этих типов говорит, что мы можем безопасно изменять один и тот же объект из нескольких мест. Имея &Mutex, вы можете получить из него &mut T и изменить объект, но сам Mutex передается по константной ссылке (&, а не &mut), создавая иллюзию, что объект неизменяем. Сделано так потому, что borrow checker просто не разрешит создать несколько неконстантных ссылок на один и тот же объект. Выглядит не очень очевидно, но не так уж и страшно.
> а &mut str — неизменяемый (immutable).
Да, тип str вообще особенный и вносит много путаницы.
> Чрезмерно кратко поименованные типы и ключевые слова, которые не передают их назначение, как, например, Vec и Cell.
Дело вкуса. При желании можно переименовать тип при импортировании.
> Большинство думает, что Rust имеет два типа строк…
Нет ничего плохого в том, чтобы разграничить разные типы строк. String — строка в utf-8. CString — нуль-терминированная строка в произвольной кодировке (прямо как в C). OsString — строка в формате, используемом в нативном API текущей ОС. С преобразованиями между этими типами проблем нет, везде есть соответствующие методы. Ну, а &str, &CStr и &OsStr — это позаимствованные строки в соответствующих форматах.
> Повсеместное неявное преобразование (типа) означает, что справочные документы практически бесполезны. Можно взять Vec, поскольку он неявным образом преобразует в &[T], например, и можно использовать для циклов с Vec и &[T], но результат будет немного различающимся в зависимости от того, что используется.
Видимо, имеется в виду Deref. Во-первых, реализованный Deref описывается в документации типа. Во-вторых, не Vec, а &Vec автоматически преобразовывается к &[T]. И результат итерирования по &Vec и &[T] будет одинаковым. А если итерироваться по Vec, то результат, конечно, будет другой (вектор будет разрушен). А вот Vec к &Vec автоматически преобразовываться не будет.
> Не совсем повсеместное преобразование (типа) означает, что ваш код оказывается замусоренным тарабарщиной вроде &*some_var (который преобразует интеллектуальный указатель в ссылку) и &some_var[..] (это — та самая магическая формула, которая преобразует Vec в &[T] или String в &str).
Неправда. Благодаря упомянутому выше Deref можно писать просто &some_var в обоих случаях.
> Дублирующие элементы, такие как, например, структуры кортежа и модулеподобные структуры
Tuple-structs позволяют делать структуры без именования полей, что вполне может быть осмысленно в некоторых случаях. Unit-like structs (структуры без полей) используются для построения API, например, чтобы выразить глобальный ресурс, захваченный мьютексом (часто используется в обертках сишных библиотек).
> Типы суммы — не enum. Хватит притворяться С.
Согласен, называть tagged union enum-ом — решение плохое.
> Поскольку он статически связывает всё (спасибо, Go, за выпуск этой модной штучки), вы получите тысячи, вероятно, устаревших копий кольца на вашем компьютере.
Можно делать динамическую линковку, если кому-то хочется.
> Действительно, он статически связывает почти всё. Он динамически связывает вашу программу с библиотекой, в результате чего ваши исполняемые файлы не являются, на самом деле, самодостаточными.
В оригинале имеется в виду динамическая линковка с libc. Делать это статически — вещь весьма специфическая.
> Нет пространства имён в поставке. Всё получает «креативные» имена, как, например, «ring» (набор криптопримитивов) или «serde» («serialization and deserialization» («сериализация и десериализация»), ничего?).
Согласен. В копилку: «select» — интерфейс к HTML-парсеру.
> Обобщённые типы очень распространены, и они по существу копируются и вставляются для каждого конкретного типа, с которым они используются (спасибо тебе, С++, что сделал это популярным). Вы знаете то, что делает компиляцию по сути тем же самым кодом часто ещё более болезненной?
Какие альтернативы предлагаете?
> rustc работает медленно…
Претензии к медленной компиляции, нехватке поддерживаемых платформ, отсутствию инкрементальной компиляции (кстати, в nightly ее уже начали внедрять) и хорошей IDE справедливы, но временны. Язык еще очень молодой.
use std::ascii::AsciiExt;
let mut str_owned = "qwe".to_owned();
let str_borrowed: &mut str = &mut str_owned[..];
str_borrowed.make_ascii_uppercase();
println!("{}", str_borrowed);
//QWE
fn make_ascii_uppercase(&mut self) {
let me: &mut [u8] = unsafe { mem::transmute(self) };
me.make_ascii_uppercase()
}
Т.е. на самом деле для этого необходимо преобразовать в &mut [u8]. Напрямую поменять что-то в &mut str действительно нельзя, просто нет методов для этого. Это из-за того, что нельзя менять количество байтов в позаимствованной строке (она вполне может быть подстрокой другой строки), а редактирование UTF-8 в общем случае может менять количество байтов практически при любой операции.
Тем не менее, &mut str — не то же самое, что &str, потому что &str в &mut [u8] преобразовать сложнее. Так что и тут mut вполне означает изменяемость.
XML и CSS уже языки программирования? О времена, о нравы!
А на деле-то отстой!!!
И это хорошо и правильно.
Camel-регистр никуда не годится:
XMLHttpRequest
HTMLHRElement
Так и хочется вставить мем «вы серьезно?». Что не так в этом камеле? Их два вида, и в джава-подобных языках рекомендуется называть имена классов с большой буквы. Именно рекомендуется.
Почему нет такого же упрёка к шарпу? Там даже методы рекомендуется называть с большой буквы, причем уже рекомендуется настоятельно и навязчиво, ведь у всех стоит решарпер…
В общем, раз автор и переводчик соизволили высказать личные мнения — выскажу и я. КГ/АМ.
PS: С большой долей вероятности автор пишет на паскале/дельфи или на ассемблере. Я так думаю…
XmlHttpRequest
HtmlHrElement
Чтобы понять суть — вместо каждой буквы аббревиатуры напишите нормальным камелкейсом слово, её означающее. И всё станет на свои места.
HtmlRequest.
var HTML = getHTML()
А в underscore стиле как писать? Ну на руби там.
get_HTML()
Или, может, так?
get_h_t_m_L()
С большой долей вероятности автор пишет на паскале/дельфи
Интересно, почему? Borland style guide как раз Camel рекомендует со всеми заглавными.
• Например, данная публикация была закрыта разработчиками немедленно как «WONTFIX» («Проблема есть, но решаться не будет»), несмотря на большое число пользователей, поддержавших её.
Если набраться мужества и пролистать до конца, то можно увидеть, то её таки решили.
• '0', 0 и 0.0 являются неправильными, но '0.0' — правильным.
Что-что, простите?
Про vararg — да, неудобно.
про индексацию с 1 — вкусовщина. Привык за полчаса
Про глобальные и локальные переменные так же вкусовщина. В итоге область видимости переменных работает куда удобнее. Ну и вообще это видимо настолько не удобно что в ES6 добавили let (что делает, если кто не знает, то же самое что в lua работает из коробки) и попросили забыть про var.
З.Ы. спасибо за перевод
Функция Conj действует несообразно в зависимости от предусмотренного типа (присоединяет к началу векторов и заголовку списков).
Посмеялся. Наоборот как раз, функция действует сообразно типу. Делает это оптимальным способом для типа. При том, что векторы не являются последовательностями (sequences), а список (list) является. Наиболее быстрым способом вставить в список является присоединение в начало списка, в векторе в конец. И еще есть функция cons.
cons работает с последовательностями, всегда возвращает последовательность, conj работает с коллекциями, возвращает тот же тип который был передан.
Синтаксис Lisp не позволяет видеть, что представляет собой функция и т.д. — Нет визуального различия.
Еще больше посмеялся, просто потому что промпт или гугл-переводчик ничего не знают видимо о DSL или lisp?
Java и Делегаты: зачем???
Анонимные классы не такие уж и большие, или вы декомпозировать не умеете? Декомпозируйте на подзадачи и код будет меньше и приятнее.
Или юзайте лямбда, кто мешает.
Если так подумать для реализаций одних и тех же фич разных языках почти всегда достаточно имеющегося функционала, с другой стороны, а нам это нужно?
Поскольку «nil» («ноль») может представлять любой тип, то это полностью разрушает систему типов.
nil не может собой представлять любой тип, он может быть значением указателя на любой тип
Сравнение интерфейса с нулём проверяет, является ли *типом* интерфейса ноль, а не его значение. Таким образом формируется ловушка, в которую попадался каждый Go-программист:
ЛОЛЧТО? Интерфейс — указатель на структуру, содержащую два поля — дескриптор типа и указатель на данные, проверяется соответсвие указателя на эту структуру nil'y, а не указатель на данные. RTFM
Тип ошибки Go является просто интерфейсом для функции, возвращающей строку.
И? <зануда> и не функции, а структуры с данным методом</зануда>
В Go отсутствуют исключения, а вместо этого везде используются коды ошибок, что приводит к повторяющемуся шаблону контроля ошибок
Ну, ошибки можно не только на nil проверять…
Задержанные функции могут выполнить запись в возвращаемые значения, имеющие имена функций, что может привести к неожиданностям:
ССЗБ — Сам Себе Злобный Буратино
Остально даже коментировать не буду, хотя за остальные языки тоже обидно
• Программный интерфейс данных (Date API) считается устаревшим, но до сих пор повсеместно используется. Плана замены нет.
Интерфейс данных? Date != data
Не говоря уже о том, что замена есть (Java Time API), но это не к переводу уже.
Авторов. Там не один автор.
Сожрут машинный перевод, или нет?
Будут ли обсуждать статью, которую сложно понять не прочитав оригинал?
Будут ли упоминать в обсуждении в основном кривой перевод или в основном недостатки оригинальной статьи?
Заметят ли, что сначала clang перевели как шумиху, а потом, после того, как в коментариях по этому поводу высказались — поправили перевод слова clang с шумиха на случайные тролли?
Это и многое другое в грядущей на хабре публикации об исследовании влияния статьи с машинным переводом на аудиторию. Такая публикация — единственный способ спасти репутацию переводчика. Её надо написать, даже если ничего такого никто и не планировал.
Обычно когда авторы переводов косячат — они в комментах активно соглашаются с замечаниями, правят на ходу статью. А тут — тишина.
Я на самом деле читал статью только про PHP и Java и могу назвать необоснованными аргументы, помеченные как Исправлено в PHP 7, и тем более Исправлено в PHP 5, который был выпущен в 2004 (!) году
К критике Java, претензий меньше, хотя так же считаю несерьезными обвинения в том, что уже исправлено
Проблема отступов — обычно её называют «проблемой пробелов»
Да заебали уже. Нет никакой проблемы отступов.
Проблема в пробелах — это пробел в проблеме.
VBA: Поддерживает GoTo.
Python: Прерывание или продолжение по метке отсутствуют.
Автор ещё не определился, крестик снять или трусы надеть, предпочитает жить с шизофренией.
И вообще, по python (а имею сопоставимый объём опыта и в нём, и в php и в js) такое ощущение, что автор к трём-четырём реально перечисленным проблемам высосал из пальца ещё десяток, основанных на вкусовых предпочтениях, чтобы никому не показалось, что python действительно хороший язык. По он php тоже нафантазировал достаточно много, раздув список реальных проблем раза в два. Насчёт остальных языков не скажу, т.к. использовал их мельком.
Нет делегатов; каждый раз, когда нужен указатель на функцию, приходится реализовывать заводскую разработку
«Заводскую разработку»? Нет, вы это серьезно?!
Когда дошел до С, начал что-то подозревать.
Массивы переменной длины, как правило, помещаются в стек, а это означает, что передача при слишком большом размере небезопасна
Где автор видел, что массивы переменной длинны помещаются в стек? Как потом менеджить указатель на этот самый стек? (Певый вопрос из многих, который пришел в голову)
Когда дошел до Rust, понял, что половина текста написана в минуты отчаяния. Часть про Rust уж точно.
mut означает исключительный, а не изменчивый (mutable). &Mutex означает изменчивый (mutable), а &mut str — неизменяемый (immutable)
Ни одно из вышеперечисленных предложений не верно.
Изменить файл? Потребуется перекомпилировать всю вашу библиотеку. Кстати — rustc работает медленно.
Исправленно.
Поскольку он статически связывает всё (спасибо, Go, за выпуск этой модной штучки), вы получите тысячи, вероятно, устаревших копий кольца на вашем компьютере.
Не факт, что много «устаревших копий кольца» это плохо (сильно смеюсь). Что переводчик тут имел в виду, так и не понял. Наверное много статически слинкованных библиотек, которые уже обновились?
Нет пространства имён в поставке.
В какой поставке? Есть пространства имен. В Rust они называются modules и crates.
Поскольку в поставке нет никаких попыток кэширования артефактов компилятора, то вы компилируете каждую раздутую библиотеку каждый раз, когда создаёте новый проект. Я уже говорил, что rustc работает медленно?
Сейчас так ведуть себя многие менеджеры пакетов. Однако «если создавать проекты», они не имееют никаких зависимостей, поэтому для них ничего не надо компилировать.
Про многие мелкие недочеты уже промолчую
Не факт, что много «устаревших копий кольца» это плохо (сильно смеюсь). Что переводчик тут имел в виду, так и не понял.One ring to rule them all, one ring to find them,
One ring to bring them all and in the darkness bind them.
Где автор видел, что массивы переменной длинны помещаются в стек? Как потом менеджить указатель на этот самый стек? (Певый вопрос из многих, который пришел в голову)
Для этих целей существует регистры esp/rsp и ebp/rbp. С одним регистром это и правда было бы трудно, но два позволяют проворачивать такие трюки.
А еще есть такая функция как alloca
Для этих целей существует регистры esp/rsp и ebp/rbp.
Не нашел их среди своих r1-r12, sp, lr и pc, к сожалению. /irony
Вариантность символов чрезвычайно раздражает.
Должно быть «изменение сигилов чрезвычайно раздражает».
Точечное представление для методов, свойств и т.д. является хорошим делом
Что такое «точечное представление» вообще понять без оригинала не удалось. Должно быть «обращение к методам, свойствам и т. д. через точку...».
«unless» («пока не»)
unless — это «если не».
Если вам нужен квадрат, то круг не подойдет, при этом если вам нужен круг, то у квадрата будет слишком много углов. Некоторые вещи нельзя сделать так, чтобы они подходили под все задачи и требования одновременно.
Про питон — половина просто зашоренность автора, четверть — притянутые за уши кейсы, еще четверть реально неудобные вещи, но не криминальные. А вот про пару реально отстойных моментов — не упомянуто.
Кстати да. Более того, пример с отступами и вложенными if/else я бы использовал в качестве аргумента «за» отступы вместо {}
Про питон — половина просто зашоренность автора, четверть — притянутые за уши кейсы, еще четверть реально неудобные вещи, но не криминальные. А вот про пару реально отстойных моментов — не упомянуто.
Это верно для всех перечисленных языков :)
Неполная встроенная поддержка комплексных чисел: как (-1)**(0.5), так и pow(-1, 0.5) выдают ошибку вместо возврата 0+1j.
>>> (-1)**(0.5)
(6.123233995736766e-17+1j)
>>> pow(-1, 0.5)
(6.123233995736766e-17+1j)
> Объявление переменной является глобальным по умолчанию
> Разыменование на несуществующем ключе возвращает ноль вместо ошибки.
Все же не ноль, а nil, который изначально подразумевает отсутствие значения. Если хочется чуть больше безопасности можно повесить метатаблицу на _G или использовать существующий модуль — http://www.lua.org/extras/5.2/strict.lua.
> Невозможно выполнять перебор varargs
Возможно с помощью функции select.
> Операторы отличаются от выражений, а выражения не могут существовать вне операторов
И слава Богу. Выражения вне оператора присваивания словно приглашают создавать перегрузкой операторов стратегические ракеты класса космос-нога.
Замечания по Java:
>> Нет ключевого слова var для предполагаемых локальных типов (как в C#).
Появится в java 10
http://openjdk.java.net/jeps/286
>> Программный интерфейс данных (Date API) считается устаревшим, но до сих пор повсеместно используется. >> Плана замены нет.
В java8 появилось LocalDate, LocalTime, LocalDateTime. Фактически это API yoda time
http://www.oracle.com/technetwork/articles/java/jf14-date-time-2125367.html
> • Индексы массива начинаются с нуля, но индексы коллекции — с единицы.
Вообще не критично. Из соображений унификации можно указать OPTION BASE 1
>• У классов нет конструкторов, которые могут принять аргументы.
>• Невозможно перегрузить методы.
>• Нет наследования.
VBA — это Visual Basic for Application
Изначально предназначен для работы в средах приложений, перенасыщенных объектами — Excel, AutoCAD… С объектами и их свойствами можно делать многое, наворачивать еще и свой объектный слой — достаточно сложно и не нужно. Мне вполне хватает процедурных возможностей. Классы конечно создаю, особенно «наблюдатели»… with Events — но это не более 5% кода.
И в дополнение про отсутствие какого-либо наследования — если делать акцент на таких аспектах, то тогда и отсутствие множественного наследования является признаком «отстойности» многих языков.
>• Поддерживает GoTo.
Да, это рудимент. Не требуется никаких усилий, чтобы не использовать подобные рудименты. Предлагаю не считать наличие рудиментарных конструкций, без которых можно очень легко обходиться, признаками «отстойности» того или иного языка программирования.
> • `OnError Resume Next` — Yeah… Происходит именно то, что вы читаете. Обнаружена ошибка? Нет проблемы! Просто продолжайте упираться и продвигаться вперёд в следующей строке.
Именно так! — Продвиньтесь к следующей строке, в которой легко и просто разберитесь с типом возникшей ошибки. Как я указал выше, в среде приложений мы работаем с невероятным количеством объектов, каждый из которых имеет множество свойств. Т.к. в средах этих же приложений, как ни странно, кроме наших программ работают еще и пользователи, то фактическое (в конкретный момент времени) состояние объектов может резко отличаться от требуемого — нет нужной рабочей книги, или она есть, но почему-то защищена, или вместо ожидаемого активного Worksheet активным является какой-то другой Sheet… и еще масса нюансов. И что плохого если я могу поэтапно анализировать состояние среды, регламентно реагируя на ошибки сразу в этих же фрагментах кода, не перескакивая в обработчики ошибок? За OnError Resume Next разработчикам нужно нобелевскую премию выписать!
>• Свойства по умолчанию.
1) Насколько я понимаю, слегка упрощает механизм автоматизированной записи действий пользователя и написание коротких простых макросов;
2) Не используйте свойства по умолчанию в VBA-программах более 15 строк;
3) На выработку этого устойчивого навыка мне потребовалось 120 секунд, 25 лет назад — в чем проблема?
>Приведённые ниже две строки означают не одно и то же.
Dim myRange As Variant
myRange = Range(«A1»)
Set myRange = Range(«A1»)
Не используйте тип Variant там, где тип объекта очевиден — а это 99,6% кода. Знайте, что осмысленное использование Variant экономит десятки строк кода — например, Activesheet может быть как Worksheet так и какой-то другой Sheet — изначальное присвоение переменной типа Variant затем позволяет одной строкой выяснить тип активного листа Excel и понять, можно ли двигаться дальше или нужно обработать ошибку.
C#. Невозможно выполнить какие-либо операции (даже простейшие арифметические) с объектами внутри обобщённого метода (например, T plus<T>(T t1, T t2) { return t1+t2; }
В .NET 7 эту проблему, наконец-то, разрешили.
Ваш язык программирования — отстой