О чём молчат авторы «Hello, World!»-ов +13


image


Обычно адепты нового Того-самого-лучшего-языка пишут свои рекламные мини-программы для обучения и продвижения примерно так:


ageOfBob = 0
ageOfMary = 0

print("Input Bob's age: ")
read(ageOfBob)

print("Input Marry's age: ")
read(ageOfMary)

// Do the math
if (ageOfBob > ageOfMary)
   print("Bob is older than Mary by ", ageOfBob - ageOfMary, " years")
else if (ageOfBob < ageOfMary)
   print("Mary is older than Bob by ", ageOfMary - ageOfBob, " years") 
else 
   print("Mary and Bob are of the same age")

Предполагается, что новичку, заинтересовавшемуся языком, понравится очередной упрощенный вариант C-подобного синтаксиса с автоматическим приведением типов, без лишних точек с запятыми, простыми именами встроенных функций и прочее.


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


const MAX_PERSON_AGE = 120
const MIN_PERSON_AGE = 1

int getAge(string name) {
   age = 0

   print("Input ", name, "'s age: ")
   read(age)

   if (age < MIN_PERSON_AGE or age > MAX_PERSON_AGE)
      throw IncorrectAgeInputException
   else 
      return age
}

try {
   ageOfBob = getAge("Bob")
   ageOfMary = getAge("Mary")
} catch (IncorrectAgeInputException) {
      print("You're doing it wrong!")
}

// Do the math
...

Итого лёгким движением руки четыре строки кода ввода числа превратились в определение пары констант (потому как магические числа в коде — плохо) и функцию (потому как Don't Repeat Yourself), которая генерирует исключения, которые также нужно обрабатывать. А если ещё вспомнить, что функцию getAge ещё нужно покрыть хотя бы парой unit-тестов…


Такой детский пример на деле легко обобщается на широкий класс задач, связанных с обработкой внешнего ввода, когда программа получает заведомо неизвестные значения, которые могут быть чем угодно.


Теперь посмотрим, как возможности строгой типизации могут помочь решить такую задачу.


Перепишем нашу повзрослевшую программу на Ada. В Ada уже с 1983-го года есть та самая фича "если оно компилируется, значит оно работает", которой теперь рекламируют Haskell и Rust. Также программы на Ada компилируются в native-код и могут работать в том числе на микроконтроллерах в реальном времени, не на много уступая языку С по скорости выполнения. Впрочем мы отвлеклись…


with ada.text_io, ada.integer_text_io, ada.io_exceptions;
use  ada.text_io;

procedure main is
   type Age is range 1 .. 120;

   package io is new ada.text_io.integer_io(num => Age);

   ageOfBob, ageOfMary : Age;
begin
   put_line("Input Bob's age: ");
   io.get(ageOfBob);

   put_line("Input Mary's age: ");
   io.get(ageOfMary);

   -- Do the math
   if ageOfBob > ageOfMary then
      put_line("Bob is older than Mary by" & Age'Image(ageOfBob - ageOfMary) & " years");
   elsif ageOfBob < ageOfMary then
      put_line("Mary is older than Bob by" & Age'Image(ageOfMary - ageOfBob) & " years");
   elsif ageOfBob = ageOfMary then
      put_line("Mary and Bob are of the same age");
   end if;

exception
   when ada.io_exceptions.Data_Error =>
      put_line("You're doing it wrong!");
   when others => null;
end main;

По сравнению с самым простым первым вариантом этой программы был лишь добавлен новый тип Age с явно заданным диапазоном значений:


type Age is range 1 .. 120;

Также был подключен пакет ada.text_io.integer_io, параметризованный этим типом:


package io is new ada.text_io.integer_io(num => Age); 

Теперь при вызове функции io.get(ageVar), где ageVar — переменная типа Age, будет проверяться введённое пользователем число и в том случае, если оно не соответствует своему типу Age, будет генерироваться исключение Data_Error.


Часто можно услышать что язык Ada сложный, многословный и трудный для изучения. Здесь приведён пример того, как "лёгкие" на первый взгляд языки просто перекладывают часть работы на программиста, в то время как "сложные" языки, на изучение фишек которых может и вправду понадобиться больше времени, позволяют сэкономить время на отладке и проверке при реальной разработке.

Теги:



Комментарии (330):

  1. qbz
    /#10100660 / +22

    Ничего не понял, прочитав до конца. Причем тут Ада? Чем классический не раздутый хеллоу-ворлд плох для новичка? Новичек он поэтому и новичек, что потом только узнает про все остальное, а не сейчас.
    Странная статья.

    • iig
      /#10100680 / +3

      Строгая типизация == раз скомпилировалось, значит работает. Спорное утверждение, программисты на С++ могут не согласиться.

      • yarric
        /#10100722 / +3

        Строгая типизация в этом сильно помогает.

        • Apathetic
          /#10100848 / +2

          Есть какие-то результаты статистических или иных исследований в поддержку этого утверждения?

          • yarric
            /#10100898 / -1

            Та же Ada ведь не с потолка была придумана.

            • Apathetic
              /#10101088

              При всём уважении, это вообще ни разу не ответ на мой вопрос. То, что Ада является языком со статической сильной типизацией — это не доказательство того, что сильная типизация в чем-то лучше слабой. Это лишь следствие того, что все варианты языка, представленные на конкурс, были основаны на Паскале.

              • yarric
                /#10101412 / -6

                Требования к языку Ada были разработаны на основе опыта проектирования больших программных систем, так что этот язык сам по себе является стандартом, на который можно ссылаться в подобных вопросах.

                • Apathetic
                  /#10101506 / +6

                  Нет, не является.

                  • yarric
                    /#10101538

                    Ой, всё :)


                    Нет, ну если серьёзно — я не знаю ни одного другого языка, дизайн которого был бы так же хорошо обоснован на основе формальных требований, составленных по результатам опыта реальной разработки сложных систем. Есть ещё пара стандартов для языка C: MISRA C и Frama-C.

                    • Apathetic
                      /#10101616 / -2

                      Формальные требования были описаны для конкретного контекста. В другом контексте требований могут быть (и будут) совсем другими.

                    • dplsoft
                      /#10101884 / -1

                      java?

                      дизайн, скорректированный опытом реальной разработки сложных и «сверхбольших» систем на протяжении почти 20 лет. не? :)

                      • yarric
                        /#10102052

                        Java вообще задумывался как язык для программирования умных микроволновок, о сверхбольших системах авторы и не думали.

                        • dplsoft
                          /#10102722

                          но в итоге то, микроволновки выросли в майфреймы.

                          • yarric
                            /#10105606

                            Тем не менее никто не пытается её применять в медоборудовании или авиации. А какая область применения у неё на мейнфреймах?

                            • dplsoft
                              /#10105838

                              гм… «основной язык для описания бизнес-приложений», если это можно так назвать. ibm-ы традиционно выделяют отдельный процессор специально под задачи джавы. (я говорю про айбиэмовские майнфреймы, потому, что иные производители, куда-то исчезли)

                              в нашей стране я видел следующее: нашу с вами пенсию учитывают, грузовыми жд-перевозками по стране управляют, банковские платежи в цб обрабатывают.

                              ps: это такой тролинг, или вы серьезно не в курсе «области применения на майнфреймах»? давайте обсудим.

                            • dplsoft
                              /#10105854

                              Насчет медицины и авиа ничего не могу сказать, не сталкивался. Лично по мне, так си для этих целей — самое то.

                              Вы хотите сказать что ада применяется в медицине и авиа (в смысле «до сих пор»)?

                              Я не для спора, мне скорее интересна фактическая ситуация.

                              • drafterleo
                                /#10107066

                                В медицине можно выделить два полюса приложений — учётно-статистические и оперативно-мониторящие. В чистой учётке каждый извращается как может — вплоть до 1С и макросов на Excel, но чем ближе к пульсирующему в realtime телу (когда жизненно критична скорость обработки и отклика), тем больше C\C++ и меньше экзотики. Полагаю, в авиации похожая ситуация. А так, в целом, и SCADA-системы на C# пишут и ЧПУ-станки питоном программируют.

                                • yarric
                                  /#10107694 / +1

                                  Насколько мне известно, для серьёзных бизнес-задач серьёзные конторы используют специализированные языки, вроде SAP ABAP. Понимаю, что в целях экономии многие готовы писать свои системы хоть на PHP, но честно говоря, специально спроектированные инструменты вызывают гораздо больше доверия.


                                  Есть немалый список проектов, в которых используется Ada. Обычный C в mission-critical проектах не используется, используется подмножество MISRA C или Frama-C. Кстати интересно заметить, что для обеспечения надёжности эти стандарты выкинули из C много фич — к теме о бесполезных нововведениях в языках. Что касается C++, то преимущества его использования по сравнению с Ada мне не понятны, разве что программистов найти легче.

                                  • drafterleo
                                    /#10107848 / +1

                                    По поводу SAP ABAP углубляться не буду, однако замечу, что случаев удачного внедрения (выливающегося в экономический плюс) ненамного больше случаев неудачного или даже катастрофического (непомерные затраты и адские страдания рядовых пользователей, которые помимо своих основных обязанностей оказываются вынуждены обслуживать это инфомационное чудище-юдище), при том, что разработчки и внедренцы при любом раскладе получают нехилый доход (ибо казино всегда в выигрыше).

                                    Иногда мне кажется, что если бы разработка шла с нуля, снизу-вверх (пусть бы даже и c привлечением PHP :)), получилось бы куда эффективней. По крайней мере, разработчики реально бы вжились в бизнес-процессы, а не пытались навязывать «универсальное решение».

                                    Против Ada (как подхода) ничего не имею, идея синтезировать статический анализатор с компилятором вполне себе разумная мысль (нечто подобное пытаются осуществить и упомянутая Farma-C, и набирающий популярность Rust). Но ведь это же не единственный подход. Есть, например, TDD. Опять же, статический анализатор к C++ всегда можно подключить «сбоку». Это как выбор между кухонным комбайном (всё в одном) и набором специализированных устройств (блендер, соковыжималка, мясорубка и т.д.).

                                    Что касается «новых фич», уверяю, ни в одном из языков (в классической вычислительной парадигме) никогда не будет «новой фичи», которой бы до этого не было в Lisp. Да и фича, фиче рознь. По крайне мере то, что я использую из C++[11-14], (на мой взгляд) существенно понижает вероятность ошибок, повышая удобство разработки.

                                    • 0xd34df00d
                                      /#10108314 / +2

                                      Опять же, статический анализатор к C++ всегда можно подключить «сбоку».

                                      Лучше, когда статический анализ сделан гармонично с языком в виде системы типов.

                                      • drafterleo
                                        /#10108714

                                        Кто ж спорит, однако у этой гармоничности есть своя цена. В качестве аналогии — ифкуиль на уровне грамматики «заставляет» выражать свои мысли чётче и однозначней и в этом гораздо круче любого из естественных языков. Засада в том, что мало кто из реальных людей (даже теоретически) способен его выговорить (58 фонем с тонами!), свободно сочетая многомерные грамматические таблицы по вариативными правилами организации формативов.

                                        • Vjatcheslav3345
                                          /#10108936

                                          ифкуиль на уровне грамматики «заставляет» выражать свои мысли чётче и однозначней и в этом гораздо круче любого из естественных языков.

                                          Засада в том, что мало кто из реальных людей (даже теоретически) способен его выговорить

                                          А зачем собственно что то выговаривать? Главное — суметь точно мысль выразить (как в математике).
                                          Вполне можно представить себе спецификацию С++ написанную рабочей группой по языку на урезанном подмножестве ифкуиля (без фонетики, которая там создаёт проблемы — только смысл, воспринимаемый с экрана) с введёнными дополнениями, которые будут аналогами команд Git, нужными для работы редакторов и автоматического слияния веток с логическими (а не символьными) изменениями а также — разрешения конфликтов. Тогда ифкуиль и его подмножество будут соотноситься как SGML и XML.

                                          • drafterleo
                                            /#10108956

                                            без фонетики… только смысл, воспринимаемый с экрана

                                            Для этого придуман ихьтаиль (ictail) — оригинальная система письма ифкуиля :). Графический вариант, действительно, считывать проще, хотя семантические корни, основанные на котрежах согласнных фонем (да и вообще — фонотактика) и разноплановые сочетания многомерных грамматических матриц никуда не деваются.

                                        • 0xd34df00d
                                          /#10109046 / +2

                                          Кто ж спорит, однако у этой гармоничности есть своя цена. В качестве аналогии

                                          Я правильно понимаю, что эта аналогия призвана показать, что на каком-нибудь там хаскеле мало кто из реальных людей писать может?

                                          • drafterleo
                                            /#10109104

                                            На провокационные вопросы не отвечаю :). Однако обращу внимание, что в данной теме речь не о каком-нибудь хаскеле (который по сравнению с «массовыми языками» скорее непривычен, чем сложен), а про вполне конкретную Аду. Кроме того замечу, что знаком с упомянутыми языками весьма поверхностно и все мои высказывания по их поводу следует воспринимать не иначе, как личное мнение при отсутствии профессионального опыта применения.

                                            • drafterleo
                                              /#10109186 / +2

                                              P.S. Кстати, я не считаю Ada сложным языком (учитывая, что в своё время съел собаку на Object Pascal) и поэтому, если бы, вдруг, пришлось включаться в проект на этом языке, не морщился бы и не плевался. А вот, например, сказать, что достаточно хорошо знаю C++ (несмотря на то, что программирую на на нём много лет), я бы, положа руку на сердце, не рискнул ;).

                                    • netch80
                                      /#10108360

                                      Что касается «новых фич», уверяю, ни в одном из языков (в классической вычислительной парадигме) никогда не будет «новой фичи», которой бы до этого не было в Lisp.

                                      LISP до начала стандартизации Common LISP или вообще весь со всеми диалектами? (тогда — нечестно)
                                      Системы типов с автовыводом, а-ля ML, Haskell?
                                      Или это уже не "классическая вычислительная парадигма"?

                                      • drafterleo
                                        /#10108694

                                        Я скорей подразумевал Lisp как унифицированный синтаксический ассемблер (в том смысле, что программа на нём имеет максимально «плотный» доступ к своему синтаксическому дереву). Поэтому при большом желании в Lisp можно реализовать любую идею (в том числе и статический вывод типов) не выходя за рамки языка (кроме «синтаксического сахара» — всякий реализованный принцип будет иметь специфический лисповский видок :)).

                                  • dplsoft
                                    /#10109040 / +1

                                    >>Насколько мне известно, для серьёзных бизнес-задач серьёзные конторы используют специализированные языки, вроде SAP ABAP

                                    «Бизнес-задачи» бывают разные. «Бизнес-задачи» — это не только то, чем занимается «коммерция» и «бизнес».

                                    Не путайте конкретные учетные задачи, на которые заточены компоненты SAP и задачи автоматизации бизнес-процессов.

                                    Например АСУТП писать на SAP — это надо сильно удариться головой.
                                    Не стоит писать систему реального времени контроля за грузоперевозками в масштабе страны на SAP. Можно, но в здравом уме это никто делать не будет. Потому там майнфреймы IBM, DB2, Java.

                                    А вот бухгалтерию и зарплату под объемы РЖД — самое дело — SAP там лег как родной) (а на самом деле просто потому, что 1С не тянул эти объемы).

                                    ABAP хорош только в контексте учетных механизмов SAP, а как сам язык, сужу по отзывам — не очень катит супротив даже 1С.
                                    ABAP — конкурент 1С, а не Java/С++…

                    • sshikov
                      /#10102472 / +1

                      Вы знаете, я читал еще самые первые документы по Ada. Так уж сложилось — я как раз делал диплом, и записался в ГПНТБ, и почитывал все что попадалось интересного. Так вот — то что было изначально заложено, это опыт разработки сложных систем на тот момент. Т.е. грубо говоря — 70-е годы прошлого века для первой версии языка.

                      С тех пор много воды утекло, очень много. Что-то конечно в Ada меняли, но что-то и осталось с тех пор. А взгляды на то, как нужно делать сложные системы, они с тех пор могли и поменяться — сложность-то поменялась.

                      Я к тому, что наличие формальных требований — это не догма. В этой области тоже много чего изменилось с тех пор.

                      • yarric
                        /#10107706

                        В Ada тоже добавляют новые фичи, последний стандарт вышел в 2012-м году. Большинство широко используемых сейчас современных языков появились в конце 80-х — начале 90-х. В мейнстримовых языках вообще-то довольно трудно найти какую-то концепцию, которой меньше 20-ти — 30-ти лет.

                    • sergeperovsky
                      /#10107652 / +4

                      Ада — одно из величайших разочарований в моей жизни :)
                      Хорошо составленные требования были реализованы без какого-либо анализа. Есть требование — вводится соответствующая конструкция.
                      В результате, описание синтаксиса Паскаля укладывается в 30 определений, а Ада потребовала 180. Держать в голове такой компилятор не удается, а без этого производительность программиста резко падает.
                      Так что, «хорошо обоснован» еще не означает «хорошо сделан».

                      • yarric
                        /#10107722

                        Интересно тогда, во сколько определений укладывается описание C++ или Java, или Rust. Подозреваю, что не сильно меньше. При этом, например в случае с C++, всяких undefined behaviour и подводных камней явно больше.

                        • sergeperovsky
                          /#10108238 / +1

                          По моему, никто и не пытался составить формальное описание С++. Дело в том, что С++ создавался без формализованных требований. В первых изданиях своей книги Страуструп подробно описывал, что пытался (и не сумел) сделать. Ему требовался инструмент имитационного моделирования. Описание Симулы-67 он нашел, а работающую реализацию нет. Он стал дописывать С, постепенно добавляя необходимые механизмы. Работа осталась незавершенной. Но появились пользователи и первоначальная цель была отставлена.
                          ЗЫ: Борланд делал компилятор С++, там в документации, что-то похожее на формальное описание было. На полсотни страниц.

                          • yarric
                            /#10109010

                            Ну вот, к примеру, стандарт C++ 2011 — 1336 страниц. Причём за него надо будет ещё заплатить.

                            • 0xd34df00d
                              /#10109050

                              Это не формальное описание. Формальное описание — это строго математическое описание в терминах, скажем, денотационной или операционной семантики.


                              Как пример попыток.

                            • sergeperovsky
                              /#10109100 / +1

                              Это совсем другое дело.
                              Давным давно, я пытался доказывать, что язык, это не только синтаксис, но и словарь. И среди языков выиграет тот, в стандарт которого будет включена обширная библиотека.
                              Собственно, это и случилось. При сложном и, я бы сказал, неопрятном синтаксисе, С++ стал популярен, благодаря стандартизации библиотек. Это, действительно, требует сотен страниц описаний.

                              • yarric
                                /#10109164 / +1

                                Кстати такой же стандарт ISO/IEC по Ada 2012-го года почти на 400 страниц меньше — тоже с описанием библиотеки.
                                Судя по тому, что для С++ придумано много сторонних библиотек типа Qt, Boost и т. п., со стандартной библиотекой там как раз не всё гладко.

                                • sergeperovsky
                                  /#10109394

                                  Встроенные библиотеки, библиотеки сторонних разработчиков, библиотеки команды разработчиков и личные библиотеки программиста всегда были есть и будут. Идет миграция функций из частных библиотек в общие, но конца ей нет.
                                  Я говорил только о том, что в «языках первого поколения» описывался только синтаксис, а встроенная библиотека отдавалась на произвол конкретной реализации языка.
                                  Как только встала задача перехода к индустриальному производству программ и обеспечении реальной переносимости ПО, стандартизация встроенной библиотеки на уровне языка, а не его реализации, стала необходимостью.

                                  Некоторое противоречие в том, что по единству и компактности синтаксиса предпочтительнее «авторские» языки — созданные одиночками. Но создание достаточно обширной и хорошо структурированной библиотеки одиночке не под силу.
                                  Поэтому и были надежды на проект Ада: за основу берется «ортогональный» синтаксис Паскаля, позволяющий почти все минимальным количеством конструкций, и дополняется обширными хорошо оттестированными библиотеками, создающими следующий слой языка. Но расширение синтаксиса, оказалось необходимым и сделано оно было крайне неряшливо. Не просто дополнение несколькими новыми конструкциями, а многократное увеличение их количества.

          • dplsoft
            /#10101406 / +15

            прямых доказательств нет и не будет))) зато есть куча косвенных. умеющий уши да слышит))) шучю. но ситуация примерно такова и есть, имхо.

            полномасштабных исследований наверное нигде нет, разве что какой нибудь институт, который поддерживает методы оценки трудоемкости разработки, в результате своих исследований, выставит завышенные коэффициенты связанные с языком напротив языков с динамической типизацией.

            но вот проблема в том, что серьезные большие институты, ориентированные на исследование промышленных методов разработки ПО — не очень интересуются языками с динамической типизацией. ну… мне так показалось, когда я исследовал вопрос о методиках оценки трудоемкости разработки.

            я говорю о методиках оценки типа FPA (метод баллов функциональности), COCOMO / COCOMO 2, UCP (usecase point analisys? — как FPA, но только принимает на вход прецеденты использования.).

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

            и тут такая особенность: институты, которые разрабатывают эти методики нацелены на промышленные, «серьезные области» — собственно там, где методы оценки трудоемкости очень важны. те области, где сбой в работе по имеет серьезные экономические или даже материальные последствия. или где комплекс программ сложный а процессы — часто запутаны. где проблем много, даже если системы не обрабатывают массовые заявки (т.е. гуглемейл или вконтактик с одноклассниками и фейсбуками например — они не показательны ни разу — это не промышленная разработка. они массовы, огромны, но их «бизнеспроцессы» достаточно примитивны и потому легко масштабируются. они очень просты по сути, даже в сравнении с обычной СЭД, или системой бухгалтерского или складского учета).

            так вот — в этих областях традиционно(?) языки с динамической типизацией не выживают. не востребованны они теми, кто несет серьезную ответсвенность. как то вот так случилось.

            и в результате, ничего что касается языков с «динамической» типизацией, я в исследованиях больших институтов я не видел. были коэффициенты для C/C++, Java, Paskal. даже бейсик кажется был. но джаваскрипта, руби, питона там я не помню.

            занимался исследованием методов оценки лет 5 назад, может сейчас что и изменилось, поправьте если что))

            я к чему: ссылаться на статстику — нельзя. никто не будет проводить масштабные сраврительные исследования для кучки популярных в этом году технологий. простите, но пхп был популярен пять лет назад, питон был популярен в позапрошлом году. в этом руби на коне… никто не заплатит за такие исследования.

            поэтому мы можем основываться только на собственном опыте и анализе успеха длительных промышленных проектов с которыми столкнулись и в которых участвовали.

            и на модели, котрые описывают как мы ведем разработку, типовые проблемы, ситуации в работе, которые мы можем легко или сложно решить используя разные языки.

            (например, рубисты вынуждены ренерить xml кож вручную, и вручную писать правила проверки, что бы xml соответвовал требуемому xsd; на джава же этой проблемы нет вообще — на основе xsd кодогенератором делаются классы с анотациями, и при парсинге/сериализации все правила xsd проверяются автомтатически == следовательно на джава разработать алгоритмы для wsdl-вебсервисов быстрее).

            или другой прмер: при рефактоинге кода, изменнии структуры классов и их методов, для динамических языков нет методов которые позволили бы понять, где используется изменяемый класс. что бы выявить все эти места, нужно проводить масштабное тестирование, что трудоемко. а в случае языков со статической типизацией — все места использования класса, типа, метода проверяются сразу компилятором, и более того — IDE спомбна выполнить 90%работы по анализу кода за нас. == рефакторинг кода написанного на ryby/javascript это более трудоемкая процедура, чем скажем рефакторинг кода на java илиc++.

            логические рассуждения, не больше)))

            по поводу опыта могу вам сказать так: только через 8-10 лет после института, я начал понимать почему, например, на PHP очень геморройно делать большую сложную систему типа СЭД. и что проблема не в пряморукости, а в глубинных свойствах самого языка и инструментария.

            и то, я начал это понимать только после того, как сам поучаствовал аналитиком 2 года на одном проекте внедрения системыдокументооборота, написанрой на пхп, как поразбирал багрепорты, как безуспешно разработчики пытались решить эти проблемы, и как система постепенро дохла, вплоть до невозможности собрать статстику по обработке поручений за неделю в течении 6 часов.

            то что вы скептически относитесь к утверждениям, что статическая/жесткая типизация помогает контроллировать код — мне очень понятно. я сам был таким))

            но поразмыслите детально, и педантично.

            • dplsoft
              /#10101424 / +1

              PS: Прошу прощения за очепятки и «прямоток» без заглавных букв.

            • Apathetic
              /#10101612

              Мы вроде говорили о сильной/слабой, а не о статической/динамической типизациях. Ортогональные друг другу вещи, тот же Руби, о котором вы часто пишете, — язык с сильной, хоть и динамической, типизацией. Как и Python, например. При этом в C++ типизация слабая, но — статическая.

              > я сам был таким))
              Не очень понятен этот снисходительный тон.

              Скажу сразу — я сам адепт typescript, например, и мне глубоко понятно желание видеть в своем коде сильную статическую типизацию.

              Но, тем не менее, да, я скептически отношусь к утверждениям, что сильная типизация однозначно «лучше» слабой, потому что существуют разные кейсы и разные контексты применения языков. Где-то важнее надежность, которой сильная типизация безусловно способствует (хоть и не гарантирует), где-то важнее скорость разработки.

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

              • areht
                /#10101792

                > где-то важнее скорость разработки.

                «Строгая типизация == раз скомпилировалось, значит работает» — а где здесь про скорость разработки? Или про «бизнеса/заказчика в различных контекстах применения»?

                Похоже, Вы сами в какой-то момент подменили тезис на «лучший язык — со статической типизацией», который и опровергаете.

                • Apathetic
                  /#10102030

                  Во-первых, опять же, при чем тут статическая типизация? Речь в комментарии идет о сильной.
                  И я ничего не подменял. Вы цитируете мой комментарий, который является ответом уже на совершенно другое высказывание. Не надо демагогией заниматься.

                  • areht
                    /#10102780 / -2

                    Во-первых, вы не ответили на вопросы. Так с каким именно тезисом из какого комментария вы спорите то?

                    • Apathetic
                      /#10102804

                      Я вообще не спорю. Я дискутирую.
                      Прочитайте еще раз комментарий, на который я отвечал, и вопросы у вас отпадут.

                      • areht
                        /#10103022 / -2

                        То есть по делу ответить нечего, так и запишем.

                        > Я вообще не спорю. Я дискутирую.

                        > ДИСКУ?ССИЯ, -и, жен. Спор, обсуждение какого-н. вопроса на собрании, в печати, в беседе.

                        > СОФИЗМ (от греч. sophisma — уловка — выдумка, головоломка), мнимое доказательство, в котором обоснованность заключения кажущаяся, порождается чисто субъективным впечатлением, вызванным недостаточностью логического или семантического анализа.

                        • Apathetic
                          /#10103134

                          Вы сейчас демагогией занимаетесь. Повторяю: прочитайте комментарий, на который я отвечал, и ваши вопросы отпадут.

                          • areht
                            /#10104090 / -2

                            Уже отпали, что уж. Argumentum ad nauseam на мне можно не практиковать.

                            • Apathetic
                              /#10104102 / -1

                              Какой вы интересный, однако. Такое ощущение, что вы сюда в демагогии приходите упражняться =)
                              Всего доброго!

                              • areht
                                /#10105200

                                Повторяю, обвинять меня в демагогии можно сколько угодно, но от прямого ответа уклонились вы.

                                • Apathetic
                                  /#10105494

                                  Давайте я объясню попроще. Вы процитировали мой комментарий, подразумевая, что он является ответом на комментарий yarric, в то время, как на самом деле он является ответом на комментарий dplsoft. Ваш вопрос (и обвинение в том, что я выдумываю какие-то тезисы и с ними спорю) основывается на ложной предпосылке. Я указал на это. Вы настаиваете и снова обвиняете меня в уходе от ответа. Это называется демагогия =)

                                  Я в очередной раз рекомендую вам ознакомиться с комментарием dplsoft. Я отвечал на этот комментарий, и ни на какой другой.

                                  • areht
                                    /#10105756

                                    Вы отвечали на оба. А рассказывать мне что я подразумеваю не надо.

                                    • Apathetic
                                      /#10105798

                                      О, а это уже прогресс!) Осталось совершить последние усилие над собой — и таки прочитать тот самый комментарий, на который я отвечал!

                                      • areht
                                        /#10105874

                                        Прогресс? То, что вы передёргиваете и занудствуете было понятно сразу. Там же я написал, что вопросов больше не имею. Что-то ещё?

                                        • Apathetic
                                          /#10106022

                                          И это я-то передергиваю) Оставлю это на вашей совести =) Еще раз — всего доброго!

              • dplsoft
                /#10101808 / +4

                Мы вроде говорили о сильной/слабой, а не о статической/динамической типизациях.
                Ах… Гм… Был спросонок, перепутал. Погуглил. Уточнил. Осознал :)

                Крайне редко говорят про сильную и слабую типизацию.
                Вы первый или второй. Обычно говорят про динамическую-vs-статическую типизацию.

                Особой корелляции между сильной-слабой типизацией и проблемами с разработкой не отмечал.

                Проблемы с динамической типизацией изложил — с ростом объема кода, проблемы в разработке на динамических языках прастут «очень не линейно». Проблемы со статической типизацией — относительно линейно. Это мои оценки и наблюдения.

                И до тех пор, пока не будет исследований, показывающих, какая типизация действительно лучше с точки зрения, подчеркиваю, бизнеса/заказчика в различных контекстах применения, я всегда на подобные споры и попытки их разведения буду смотреть осуждающе.
                Тогда у нас дед-лок))
                Исследований нет, и наверное не будет, ибо некому за это заплатить. нет — исследований — будет постоянное осуждение. Будет осуждение — проблему скорее всего не решить. Но принимать-то архитектурные решения надо! И стажеров надо обучать! Как быть?

                Хотя согласен, в том плане, что попытки разведения неконструктивных споров надо подавлять в зародыше.

                С моей же точки зрения, если выбирать между «статикой и динамикой» в типизации при выборе языка разработки, то мой опыт говорит мне следующее: выгода зависит от объема разрабатываемого кода. ( и я сейчас буду говорить только выгодах проекта, вытекающих из минимизации трудозатрат и технических рисков. Если последствия неадекватных технических решений будут лежать на ком-то другом, или «бизнес» планирует «отскочить» до проявления проблем или «еще как-то» (вплоть до полного наплевательства на последствия, или полного одупления (непонимания лицами принимающими решения технических проблем) ) — то «бизнес», естественно, будет принимать решения совсем с других, не связаных с техническими аспектами, позиций )

                и так:
                * на коротком периоде, для небольших задач, одноразовых, скриптования поведения «жесткой части» — удобнее/выгоднее динамическая типизация. Низкий порог входа, быстрое прототипирование — позволят экономить бюджет. До тех пор, пока кривая проблем не начала расти (не сдвинулась с места), или не начался рефакторинг, или число модулей в вашей системе не выросло до двух.
                Отсюда и область применения: скрипты инициализации, тестирование, небольшие хранимки в бд, сайты с линейной логикой работы, различные примитивные СМО и пр.

                * на длинном периоде, при относительно большом коде, с рисками изменения бизнес-логики, для задач сложнее чем на одну неделю, для кода которые надо будет поддерживать — лучше сразу начать писать на языках со статической типизацией ( возможно с включением скриптов на динамических языках ). Потому что линейный рост числа проблем (а не галлопирующий экспонентой) в зависимости от объема кода — очень даже комфортен. Причем выбирать стоит те языки, у которых как можно меньше проблем с обратной совместимостью.

                А корелляции между «сильной» и «слабой» типизацией я не заметил.

                Я не могу запретить вам его осуждать, но рассуждения, особенно логически стройные, буду рад услышать.

                я сам был таким))
                Не очень понятен этот снисходительный тон.
                Я принял вас за очередного молодого адепта «новомодных языков». Извиняюсь)

                • vintage
                  /#10102004 / +7

                  На самом деле, в современных языках статическая типизация оказывается даже быстрее при написании скриптов, потому что:


                  1. на надо гуглить какое там апи у такого-то модуля — среда разработки сама адекватно всё подскажет.
                  2. не надо запускать и дебажить для того, чтобы обнаружить глупую опечатку — компилятор и даже среда разработки понимают, что ты написал, и как можно раньше рассказывают тебе о проблемах.
                  3. не надо постоянно вручную проверять и преобразовывать типы, на случай, если на вход передадут какую-то дичь. Типичный пример: String( arg ).toLowerCase()
                  4. типы вручную пишутся только там, где пользователю это важно — в остальных местах они выводятся автоматически

                  • netch80
                    /#10102140

                    > на надо гуглить какое там апи у такого-то модуля — среда разработки сама адекватно всё подскажет.

                    IDE с поддержкой динамически типизированных языков уже существуют и активно развиваются.

                    > не надо запускать и дебажить для того, чтобы обнаружить глупую опечатку — компилятор и даже среда разработки понимают, что ты написал, и как можно раньше рассказывают тебе о проблемах.

                    Аналогично, для динамически типизированных языков есть средства линтинга, и профессионалы не выпускают код без него. Для Python я с ходу могу назвать 4 таких средства, для Javascript — 2, для многих других есть встроенные анализаторы (например, в Perl исключение по use strict генерируется именно таким контролем, а не ошибкой собственно рантайма типов).

                    Но есть таки принципиальная разница. Грубо говоря, для статически типизированных языков то, что вычисляется при компиляции, будет аксиомой при выполнении (объект типа X => у его методов будет именно та сигнатура, что у класса X). Для динамически типизированных это не обязательно — Python, Javascript позволяют подменять подложку реализации на ходу. Линтинг в принципе не способен отловить такие ситуации. Их запрет для возможности статического анализа — уже вопрос административной политики при разработке, а не собственно языка.

                    > не надо постоянно вручную проверять и преобразовывать типы, на случай, если на вход передадут какую-то дичь. Типичный пример: String( arg ).toLowerCase()

                    Да, фактор существенный. Мне в этом смысле понравились правила от Hola для Javascript: например, если требуется, чтобы на входе функции было число, пишется +x, а если строка — ""+x. Рантайм умеет опознавать эти ситуации и переводить их в конверсию типа.
                    Но вот lowercase это уже за пределами обычной возможности системы типов, надо делать свой враппер.

                    > типы вручную пишутся только там, где пользователю это важно — в остальных местах они выводятся автоматически

                    Пока что это достаточно малая часть таких языков. И даже в них автоматический вывод работает не всегда и не везде адекватно. А главное — что для уверенности программиста, что тип получился именно нужный, приходится его указывать явно.

                    • vintage
                      /#10102494 / +2

                      IDE с поддержкой динамически типизированных языков уже существуют и активно развиваются.

                      Выглядит это примерно так:


                      image


                      Аналогично, для динамически типизированных языков есть средства линтинга

                      Линтеры тут ничем не помогут. Вообще, существование линтеров говорит о косяках в языке, который допускает "не кошерные" выражения. Если же речь не о линтерах, а тайпчекерах, то для них опять же нужны тайпхинты, что возвращает нас к статической типизации.


                      И даже в них автоматический вывод работает не всегда и не везде адекватно.

                      О чём опять же программисту сообщается сразу, а не когда в рантайме прилетит что-то не то.


                      А главное — что для уверенности программиста, что тип получился именно нужный, приходится его указывать явно.

                      Как правило программисту всё-равно какой там тип, лишь бы крякал как утка.

                      • staticlab
                        /#10102774

                        Линтеры существуют не только, чтобы указывать на явные косяки программиста, но и чтобы унифицировать стиль кода внутри проекта.

                        • vintage
                          /#10102866

                          Наоборот, они по определению контролируют только форму, но не содержание.

                          • staticlab
                            /#10102910

                            Это всё демагогия. Линтером сейчас называют любой статический анализатор. По ссылке статический анализатор, проверяющий семантику кода, то есть содержание. Eslint для JavaScript — линтер, в основном проверяющий стиль написания, то есть форму.

                            • vintage
                              /#10102942

                              "сообщал о подозрительных или непереносимых на другие платформы выражениях" — не тянет это на семантику.

                              • netch80
                                /#10103418

                                А что же это, если не семантика? В понятие синтаксиса уже не влазит.

                                • vintage
                                  /#10103426

                                  Но и до семантики как до луны. Типа "ставьте точки с запятой в конце строк" — это синтаксис, а "не используйте arguments" — это уже семантика?

                                  • netch80
                                    /#10103440

                                    Мнэээ… перед этим шла речь о непереносимых выражениях, например. Если кто-то напишет x<<200, где x типа int, что это, как не проблема семантики (содержания, смысла… проигнорируем сверхтонкие отличия)? Ну или пора вводить новую систему терминов.
                                    Что за arguments тут — я не понял. Имеется в виду массив всех аргументов функции в JS? Вот тут, да, это настолько специфично для языка, что ближе к синтаксису, чем к семантике. Но я таки предпочёл бы тут видеть какое-то новое слово...

                                    • vintage
                                      /#10103444

                                      Вы правы. К сожалению для JS линтеры проверяют в основном довольно бесполезные правила.

                      • netch80
                        /#10103416

                        Выглядит это примерно так:

                        Ну да. А вы считаете это недостаточным?


                        Линтеры тут ничем не помогут.

                        Я видел последующую дискуссию про то, что такое линтер. Я тут имел в виду статический анализатор любого вида, который способен опознать ситуации типа неиспользованных переменных, типичных опечаток и тому подобного. Такие средства вполне способны проанализировать код и найти, например, неверно передаваемый параметр. С Питоном у меня это реально работало.


                        Если же речь не о линтерах, а тайпчекерах, то для них опять же нужны тайпхинты,

                        Если такое средство видит, что параметр используется как индекс в списке, оно предположит, что тут должно быть целое. Если его индексируют строкой — оно должно быть совместимым со словарём. И так далее. Явные хинты тут не обязательны. Хотя, да, желательны — я бы предпочёл их видеть много где — но в последних версиях Питона, например, это уже делается.


                        О чём опять же программисту сообщается сразу, а не когда в рантайме прилетит что-то не то.

                        Это если он не сумел вывести тип. А если вывел, но не тот, что думал программист?


                        Как правило программисту всё-равно какой там тип, лишь бы крякал как утка.

                        Так в том и дело, что он хочет утку, а получается вдруг амадина. Она тоже крякает, но как-то невыразительно :)

                        • vintage
                          /#10103436

                          Ну да. А вы считаете это недостаточным?

                          Я считаю это бесполезным, чуть менее, чем полностью.


                          С Питоном у меня это реально работало.

                          Это замечательно, но это лишь малая часть того, что может обнаружить компилятор в статически типизированном языке. Кроме того, чтобы все эти тайпчекеры работали, вам так и так придётся отказаться от динамических возможностей языка.


                          Это если он не сумел вывести тип. А если вывел, но не тот, что думал программист?

                          Он не может "не суметь". Всё, что он может — вывести тип, не совместимый с другим кодом и упасть. Если не упал, значит тип совместим и не важно, что там думал программист. Например, он мог думать, что вернётся User, а вернулся Proxy, который реализован так, что мимикрирует под User. Ну и какая программисту разница, если всё работает корректно?

                          • netch80
                            /#10103450

                            Я считаю это бесполезным, чуть менее, чем полностью.

                            Почему бесполезно?
                            Оно подсказывает, какие слова тут можно подставить, и умеет их дополнять. Также — показывает имена и типы аргументов, по которым можно понять, что и как задавать.
                            Оно может анализировать код и показывать ошибочные (например, опечатка в имени метода) или подозрительные конструкции.
                            Я не знаю, может, Вы имеете в виду какую-то злобную специфику JS. Я с ним слишком мало работал, чтобы знать такие тонкости. Но для Питона и для >95% случаев меня функциональность таких средств устраивает; когда она не работает — уже описывал раньше — когда я сам как автор кода вмешиваюсь в логику и делаю её изменчивой в рантайме.


                            Кроме того, чтобы все эти тайпчекеры работали, вам так и так придётся отказаться от динамических возможностей языка.

                            В большинстве случаев — да. Я не могу, например, писать


                            if isinstance(max_time, str):
                                max_time = int(max_time)

                            да и безусловную конверсию лучше не применять (хотя если средство хоть чем-то умнее крышки дубового стола, оно будет работать в логике, аналогичной Static Single Assignment).


                            Или, я не смогу использовать присвоение некоторой переменной одного из трёх значений True, False или None (у меня это долго был любимый приём) — оно выведет тип для этого значения, только если придумает внутри себя enum, а так как все три в Питоне это синглтоны двух разных типов, ему будет сложновато это сделать.


                            Но таких случаев в реальной практике оказалось ой немного. А вот простые варианты типа "в этой переменной всегда целое" оно вывело бы на ура. Точно так же как упомянутая рядом схема Хиндли-Милнера работает в ML и семействе.


                            Он не может "не суметь".

                            См. выше пример с конверсией в целое на ходу. Вывод типа "местами снег, местами град, местами variant — или int, или str" и есть то "не шмогла".


                            Ну и какая программисту разница, если всё работает корректно?

                            Разница в том, что мимикрия подобного рода означает слишком динамическую типизацию. И в Питоне, и в JS это поиск по названию метода в цепочках словарей методов суперклассов (прототипов).


                            Если мы вводим синтаксическую поддержку статической типизации, её лучше иметь в вариантах указания "тут постарайся оптимизировать" или "тут ты обязан вывести конкретный целочисленный тип, а его размер, так уж и быть, я тебе доверю выбирать".

                            • vintage
                              /#10103654

                              Почему бесполезно?

                              Потому, что выдаёт вообще всё, что угодно, кроме того, что там в объекте действительно есть. Потыкавшись в эту менюшку, быстро отучаешься использовать подсказки.


                              показывает имена и типы аргументов,

                              Только для стандартных API и для JSDoc аннотаций (привет, статическая типизация)


                              оно выведет тип для этого значения, только если придумает внутри себя enum, а так как все три в Питоне это синглтоны двух разных типов, ему будет сложновато это сделать.

                              Эту задачу решают "типы-суммы" и "типы-произведения". TypeScript, например, это умеет. При этом он умеет ограничивать такие типы в разных ветках кода:


                              let foo : number|string = Math.random() > .5 ? '0' : 0
                              if( typeof foo === 'number' ) {
                                  console.log( foo.toFixed(2) )
                              } else {
                                  console.log( foo.toLowerString() )
                              }

                              Вывод типа "местами снег, местами град, местами variant — или int, или str" и есть то "не шмогла".

                              Как программист написал — так оно и вывело. Или приведите пример, что ли.


                              Разница в том, что мимикрия подобного рода означает слишком динамическую типизацию.

                              Скорее динамическую диспетчеризацию (которая приятно дополняет статическую типизацию). Без неё многие задачи вообще не решаются.

                              • netch80
                                /#10103904

                                Потому, что выдаёт вообще всё, что угодно, кроме того, что там в объекте действительно есть.

                                Насколько я вижу, всё, что он выдал там, действительно есть в объекте (то есть, при вызове по имени будет поднято по цепочке прототипов и найдено). Да, их много, но самое важное находится вверху списка. Если бы не было такой сортировки, разбираться было бы в разы сложнее.


                                Только для стандартных API и для JSDoc аннотаций (привет, статическая типизация)

                                Так это и хорошо, что он умеет читать эти аннотации. Проверить соответствие аннотации сути одной функции просто и это локальное действие, не требуется никуда далеко заглядывать, и потом опираться на эту аннотацию — это как раз то, как это всё может работать в рантайме с "высочайшей" динамичностью типизации.


                                Эту задачу решают "типы-суммы" и "типы-произведения". TypeScript, например, это умеет.

                                Хорошо, значит, прогресс в эту сторону идёт.


                                Скорее динамическую диспетчеризацию (которая приятно дополняет статическую типизацию).

                                Да, это правильный термин для данного случая.

                                • vintage
                                  /#10103964

                                  Насколько я вижу, всё, что он выдал там, действительно есть в объекте

                                  Нету там этого. Уж поверьте мне на слово :-) Он просто нашёл левый файл, где встречается одноимённый ключ объекта:


                                          express:{
                                              tasks:['express:src'],
                                              options:{
                                                  spawn:false
                                              },
                                              files:["**/*.js"]
                                          },

                            • 0xd34df00d
                              /#10105008

                              Разница в том, что мимикрия подобного рода означает слишком динамическую типизацию. И в Питоне, и в JS это поиск по названию метода в цепочках словарей методов суперклассов (прототипов).

                              А если в хаскеле выведется Userlike a, то это статическая или динамическая типизация? Словарик с методами-то таскать придётся!

                    • 0xd34df00d
                      /#10102834 / +3

                      Пока что это достаточно малая часть таких языков. И даже в них автоматический вывод работает не всегда и не везде адекватно.

                      Хиндли-Милнеру лет 30. Работает адекватно во всяких ML'ях и прочих хаскелях и не требует аннотаций в подавляющем большинстве случаев.


                      А главное — что для уверенности программиста, что тип получился именно нужный, приходится его указывать явно.

                      Если тип выведется неправильно, то с окружающим контекстом он будет несовместим, и рано или поздно вы получите ошибку компиляции. Типы (топ-левел-функций) лучше указывать потому, что типы — это документация, да и явное указание типов позволяет сделать более читабельные сообщения об ошибках типизации (вы накладываете больше констрейнтов, у тайпчекера меньше вариантов).

                      • netch80
                        /#10103430

                        Я таки слишком неясно выразился. Имелось в виду, что программист ошибётся в какой-то мелочи, и результатом станет не тот тип, который ожидался. Явное называние ожидаемого типа в этом случае является дополнительной защитой со стороны программиста против собственных ошибок. (Ну и против ошибок компилятора, которые всегда есть, но вероятность в каждом конкретном случае ниже на несколько порядков...)


                        Типы (топ-левел-функций) лучше указывать потому, что типы — это документация, да и явное указание типов позволяет сделать более читабельные сообщения об ошибках типизации (вы накладываете больше констрейнтов, у тайпчекера меньше вариантов).

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

                        • 0xd34df00d
                          /#10104996

                          Имелось в виду, что программист ошибётся в какой-то мелочи, и результатом станет не тот тип, который ожидался.

                          Так это либо будет ошибкой типизации где-то позже, либо не будет ошибкой типизации и семантически (на самом деле не всегда, но в подавляющем большинстве случаев так).


                          Да, это тот же самый принцип, что я описал абзацем выше.

                          Ну, учитывая вышесказанное — не совсем.


                          Но и типы промежуточных переменных — это такая же документация

                          Только она уже не столь важна. Типы топ-левел-байндингов полезны потому, что именно их вы будете дёргать в вызывающем коде, а остальное — это детали реализации.

              • 0xd34df00d
                /#10101994 / +3

                Статические строгие системы типов выигрывают и с точки зрения скорости разработки, начиная с определённого размера кодовой базы и команды, потому что цена внесения изменений как функция от этих параметров растёт медленнее.

          • max1gu
            /#10101728 / +2

            Лехко. Какие-то странные люди, которые до этого делали Delphi, а затем c#, придумали TypeScript. Так вот сам попробовал: 90% глюков отлавливается на этапе компиляции остается только вопрос неправильнлого алгоритма.
            Ещё одни странные люди, сменив версию Ангулара с 1 на 2, тоже перешли на TypeScript (жесткая типизация). Наверное, им надоело есть кактус.

          • 0xd34df00d
            /#10101986 / +2

            Весь смысл статической строгой типизации в том, чтобы до исполнения отсекать некорректные программы.

        • franzose
          /#10103520

          Строгая типизация не означает, что в рантайме у вас внезапно что-нибудь не отвалится)

      • 0xd34df00d
        /#10101984 / +3

        В C++ нет строгой типизации.

        • netch80
          /#10102094 / +3

          Строгость типизации — понятие достаточно относительное. По сравнению с JavaScript, где преобразование между числом и строкой — норма, C++ строго типизирован, а по сравнению с Go, где даже если int 32-битный, то преобразовывать между int и int32 можно только явно — нестрого типизирован.
          Поэтому, при рассмотрении строгости типизации лучше вводить несколько канонических уровней и сравнивать с ними:
          1. Вообще никаких неявных конверсий (Go, или близко к нему).
          2. Конверсии по умолчанию — между числами, или только явно разрешённые функции, или только в особых контекстах (основной компилируемый майнстрим, C++, C#, Java и т.п.)
          3. Размыта граница между строкой и тем, что она представляет (JavaScript, Perl...)
          4. Вообще всё есть строка, оптимизации есть, но это принципиально не отменяют (sh, Tcl...)

          • 0xd34df00d
            /#10102840

            Ну, я бы не стал ставить C++ в один ряд с C# и Java по строгости типизации при всей моей любви к нему, и конверсии между разными скалярными типами — не единственный аргумент. Больше непроверяемых кастов, операторы приведения и implicit-конструкторы, всякое такое счастье.


            Строгость, конечно, понятие относительное, но множество имеющихся языков известно, поэтому можно рассматривать строгость типизации в контексте этого множества, где на вершине всякие там хаскели-идрисы (ну вот хочется почему-то строгость связать ещё и с выразительной силой системы типов, не знаю, почему), а C++ где-то в середине.

      • Antervis
        /#10102898

        не могут. С++ не является строго типизированным языком

    • panteleymonov
      /#10100718 / +1

      Есть случаи когда человек так и остается «новичком» используя только короткие шаблоны языка/тулзы/фрейморка.

    • yarric
      /#10100724 / -1

      Плох не хеллоу-ворлд, а языки, которые как-будто делают с целью упрощения написания хеллоу-ворлд-ов и написания красивых, но далёких от жизни туториалов.


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

      • alexkunin
        /#10100878 / +1

        А можете привести несколько примеров языков, «которые как-будто делают с целью упрощения написания хеллоу-ворлд-ов и написания красивых, но далёких от жизни туториалов»?

        • yarric
          /#10100910 / -2

          Синтатиксис и семантика примера из статьи демонстрирует аналогичный код на многих современных распространённых языках программирования.

          • alexkunin
            /#10100960 / +3

            Это понятно из статьи, спасибо. Я прошу привести примеры «нового Того-самого-лучшего-языка», желательно несколько. А то пока обсуждаются отличия Ады от чего-то абстрактного.

            • yarric
              /#10100992 / -1

              Прошу прощения, не хочу показывать пальцем и создавать кому-либо антирекламу, пост не для этого написан.

              • alexkunin
                /#10101022 / +3

                Речь не о человеке, не о религии, и т.д. Мы говорим о языках программирования — продуманных системах, спроектированных и использующихся множеством людей. И разговор происходит на техническом ресурсе для профессионалов.

                А пока что вы в статье сравниваете конкретный язык с придуманным негативным кейсом. Очень знаете ли похоже на «Ариэль вс. Обычный стиральный порошок».

                • yarric
                  /#10101416 / -1

                  Вы сможете привести улучшенную версию программы из моего примера на каком-нибудь из современных распространённых языков программирования вроде Java или С#?

                  • alexkunin
                    /#10101440 / +3

                    Я не хочу ничего приводить, я ничего не утверждал о хорошести или плохости других языков. Я хочу увидеть от вас пример того, что, как вы утверждаете, имеет место быть.

                    • yarric
                      /#10101446 / -1

                      Пример языка, в которых используется обработка ошибок на основе условий и исключений, как в примере? Java, C#, C++ и т. д.

                      • alexkunin
                        /#10101460 / +2

                        Т.е. вы утверждаете, что Java, C#, C++ — это те, «которые как-будто делают с целью упрощения написания хеллоу-ворлд-ов и написания красивых, но далёких от жизни туториалов»?

                        Ясно, спасибо, ваша мысль ясна.

                        • yarric
                          /#10101502 / -2

                          Java, C#, C++ — примеры языков, в которых используется обработка ошибок на основе условий и исключений, если с первого раза было не понятно.

                          • alexkunin
                            /#10101524 / +5

                            А ада с помощью духа святого выходит из щекотливых ситуаций, стало быть?

                            • yarric
                              /#10101542

                              Ada ещё добавляет проверки диапазонов на основе типов данных.

                              • areht
                                /#10101976 / +2

                                А это как и зачем?
                                Запретить вводить людей младше года и старше 120 — это совершенно искусственный пример, хуже Hello World. А в реальности это зачем?

                                • yarric
                                  /#10102018 / -1

                                  Лучше писать проверки диапазона руками в коде? Возможно, дело вкуса.

                                  • areht
                                    /#10102064

                                    Это из серии «предполагается, что новичку, заинтересовавшемуся языком, понравится очередной упрощенный вариант»?

                                    Не знаю на счёт «лучше», но после «вынесите границы в настроечки!» вписывать эти проверки точно не хочется.

                                • vintage
                                  /#10102020 / -1

                                  У вас в любом случае будут ограничения диапазонов. Заданные вами или компилятором или архитектурой процессора. Максимально компактные диапазоны позволяют оптимизировать вычисление и хранение данных, обнаруживать большее число ошибок. Разумеется число 120 неоправданно занижено. А вот диапазон {0… 256} выглядит вполне разумно на ближайшие 100 лет.

                                  • iig
                                    /#10102428

                                    Задавать возраст таким образом — готовый антипример. Особенно в 21 веке, когда проблема 2000 далеко позади, а проблема 2038 приближается.

                                    • vintage
                                      /#10102502

                                      И что вы имеете против такого задания возраста?

                                      • iig
                                        /#10103280 / +1

                                        Это приблизительно как придумать свою реализацию целочисленной арифметики, причём на bash и в столбик. И это в 21 веке. Возраст человека измеряют от дня рождения, так что детализацию возраста, если по уму, нужно делать до дня. А чтобы не наступать на грабли типа 29 февраля, лучше брать стандартное, с детализацией до секунды.

                                        • vintage
                                          /#10103304

                                          Вот именно, что замеряют. И результатом такого замера является значение типа "возраст" с соответствующими ограничениями. Если замеренное значение не вписывается в эти ограничения, то это повод бить тревогу.

                                          • iig
                                            /#10103310 / +1

                                            Вот зачем-то в программе делается сравнение возрастов. Алиса и Боб родились в один год. Алиса родилась 1 января. Боб родился 31 декабря. Кто из них старше? В модели, где все округляется до года, они одного возраста.

                                            • vintage
                                              /#10103392

                                              Почему формула сравнения именно такая — вопрос к тому, кто устанавливает правила. Возможно в какой-то специфической области сравнение должно быть именно такое. Но суть ведь не в том, как надо сравнивать возраста людей.

                                              • iig
                                                /#10103686

                                                Ок, пусть будет, тем более что это хелловорлд :). И какой профит в использовании такого типа-поддиапазона int? Компилятор сгенерирует код, который при каждом присваивании будет проверять диапазон и кидать exception? А для float так тоже можно? А диапазон может состоять из поддиапазонов? А если поддиапазонов maxint/2? А если присваивание в цикле?
                                                КМК, лучше условия проверять явно и там где это необходимо.

                                                • oxidmod
                                                  /#10103716

                                                  Все зависит от того в скольких в местах вам проверить нужно. Смотрите на єто на как VO. Раз он создался, значит он 100% валидный.

                                                • vintage
                                                  /#10103972

                                                  Многие проверки можно выкинуть, когда точно знаешь какие диапазоны где приходят. Так что единственное место, где проверки останутся — на входе в приложения, но они там и так по любому будут. Но тут их хотябы компилятор сам сгенерирует, а не программист вручную.

                                                  • iig
                                                    /#10104138

                                                    Я программист ненастоящий… И подобная компиляторная магия, как по мне, особенность, которой лучше избегать. Если нужна проверка входных данных — почему бы её не сделать как нужно? Например, если логика требует не exception, а специального кода возврата? Если сгорел датчик, например — перезагружаться?

                                                    • vintage
                                                      /#10104594

                                                      try-catch позволит вам обработать нештатную ситуацию по своему.

                                                      • iig
                                                        /#10106588

                                                        Теперь понятно, откуда берутся программы, внезапно кидающие невнятный exception, но продолжающие как бы работать.

                                                        • vintage
                                                          /#10106698

                                                          У вас какое-то странное представление об обработке исключений.

                                                    • 0xd34df00d
                                                      /#10105018

                                                      Это вполне может быть не компиляторной магией, а магией системы типов, и лучше научиться ей пользоваться.

    • Umr001
      /#10100728 / -24

      ПОМОЕМУ МОРАЛЬ ВПОЛНЕ ВЫВЕДЕНА В КОНЦЕ СТАТЬИ АЛЕ

  2. staticlab
    /#10100678 / +3

    Хорошо, а покажете, как будет выглядеть на Аде такой код?


    const MALE = 'M';
    const FEMALE = 'F';
    const PENSION_AGE = {
        [MALE]: 65,
        [FEMALE]: 60
    };
    
    const pensioners = persons.filter(person => person.age > PENSION_AGE[person.gender]);
    
    console.log('Всего пенсионеров:', pensioners.length);
    
    pensioners.forEach(pensioner => {
        console.log(pensioner.name);
    });

    • vintage
      /#10100742 / -14

      А зачем на Аде писать говнокод?


      1. persons должен уже содержать нормализованные объекты, а не сырые данные, полученные с сервера. Иначе при изменении ответа сервера вам придётся рефакторить код всего приложения. А поддержать несколько серверов вообще не представляется возможным.
      2. Для итерирования есть удобные циклы с полноценной поддержкой break и continue. Незачем лепить замыкания на ровном месте.

      • qw1
        /#10100826 / +4

        1. Не всегда программист может влиять на серверный код. Например, сервером может выступать API «одноклассников» и задача — посчитать количество пенсионеров в друзьях.

        2. Я много программировал до и после удобного использования замыканий. Разница огромная. Где раньше надо было написать портянку циклов с break, continue, и пятёркой вспомогательных переменных, сейчас без напряжения мозга просто пишешь, что ты хочешь получить, сберегая мыслительные ресурсы для остальной части задачи.

        Как по мне, поддержка запросов к коллекциям сейчас является необходимой чертой современного языка. Даже мастодонты java и c++ сдались и ввели эту поддержку. Это как раньше были языки без поддержки рекурсии и динамической памяти, но вымерли.

        • vintage
          /#10100870 / -8

          1. О том и речь, что программист должен изолировать от приложения то, на что он не влияет — ввод пользователя и ответ сервера.


          2. Циклы не требуют каких-то особых "мыслительных ресурсов". Написанный вами код ничем от циклов не отливается. Ну вот совсем. Только отлаживать его — то ещё "удовольствие". ни промежуточные результаты выполнения не посмотреть, ни по шагам пройтись, ни даже прочитать содержимое переменных из родительского скоупа, на которые нет ссылки из вложенного (хвала JIT).

          А как по мне — обобщённое программирование и исполнение кода времени компиляции являются необходимыми чертами современного языка :-) А ещё, как по мне, forEach — не является "запросом к коллекции", а является он обычным циклом, но зачем-то сделанным на редкость неудобным.

          • qw1
            /#10101238 / +6

            Циклы не требуют каких-то особых «мыслительных ресурсов». Написанный вами код ничем от циклов не отличается
            Банально устаёшь писать длинные тупые циклы, где нужно найти сумму элементов, максимальный элемент, минимальный среди максимальных. Внимание ослабевает, сажаешь ошибки. Проще написать запрос в декларативном стиле, что тебе нужно от данных, и идти дальше, не заостряя внимания на подобных задачах.
            Только отлаживать его — то ещё «удовольствие». ни промежуточные результаты выполнения не посмотреть, ни по шагам пройтись, ни даже прочитать содержимое переменных из родительского скоупа, на которые нет ссылки из вложенного (хвала JIT).
            Конкретно в Visual Studio (C#/C++) в режиме DEBUG нет никаких проблем: брейкпоинты можно ставить на любой оператор внутри лямбды, переключая контекст в окне Call Stack, можно добраться до любых переменных в watches. Если где-то это не так, это проблема IDE, а не подхода в целом.

            • JekaMas
              /#10101350 / +4

              К сожалению, это правда.
              Два года разработки на golang, где все на циклах и очень мало обобщений, и сейчас отдыхаю, изучая python. Да, он медленнее, не такой клевый для параллельного кода, но насколько же быстрее попробовать какую-то идею! Одна-две строки, вместо десятка строк кода, который может быть и выкинешь после…

            • vintage
              /#10101392

              Проще написать запрос в декларативном стиле, что тебе нужно от данных, и идти дальше

              const users_by_name = users.reduce( ( index , user )=> {
                  const name = `${ user.name_first() } ${ user.name_last() }`
                  return { ...index , [ name ] : user }
              } , {} )
              
              const users_by_age = users.reduce( ( index , user )=> {
                  const age = user.age()
                  return { ...index , [ age ] : [ ...( index[ age ] || [] ) ,  user ] }
              } , {} )

              const users_by_name = {}
              const users_by_age = {}
              
              for( let user of users ) {
                  const name = `${ user.name_first() } ${ user.name_last() }`
                  users_by_name[ name ] = user
              
                  const age = user.age()
                  if( users_by_age[ age ] ) users_by_age[ age ].push( user )
                  else users_by_age[ age ] = [ user ]
              }

              Конкретно в Visual Studio (C#/C++) в режиме DEBUG нет никаких проблем

              Это замечательно, но человек привёл пример на JS.

              • qw1
                /#10101430

                Это замечательно, но человек привёл пример на JS
                То есть, с лямбдами писать пока рановато, потому что ваш IDE их хуже поддерживает, чем классический императивный код. Ну, ок.

                • vintage
                  /#10101578 / -1

                  IDE тут, к сожалению, ни при чём. Это свойства языка / виртуальной машины.

                  • qw1
                    /#10101920 / +1

                    Ставить брейкпоинты не на строку целиком, а на оператор внутри строки — это свойство IDE.

                    Не вижу никаких проблем сделать DEBUG-режим запуска VM, в котором будут фиксироваться стек-фреймы и их контекст. Чтобы дебаггер мог получить список стекфреймов, отобразить его в отдельном окне и двойным кликом переключать контекст так, чтобы при наведении мыши на переменные (или добавление переменных в watches) их значение показывалось в соотвествии с выбранным контекстом.

                    • vintage
                      /#10102048

                      Отладчик в мире JS принадлежит виртуальной машине, а не среде разработки. Среда разработки может, конечно, поключиться к виртуальной машине и управлять отладчиком удалённо, но только в рамках его функционала.


                      Это всё уже давно реализовано. Проблема "декларативного" fluent-кода, на который сейчас многие молятся, в том, что в нём у вас промежуточные вычисления находятся на стеке, а не помещаются в какую-то переменную.


                      image


                      Вот как тут узнать, что вернул filter?

                      • qw1
                        /#10102190

                        Вот как тут узнать, что вернул filter?
                        Не знаю, как в вашей среде, но обычно в отладчиках можно выделить часть выражения
                        a.filter(i=>i>b).map(i=>i*i)
                        и нажать хоткей 'evaluate', или добавить в watches и исследовать там структуру выражения.

                        • sshikov
                          /#10102458

                          Я вам больше скажу: IDEA вполне позволяет ставить точки останова на лямбды. Если ты тыкаешь в строку типа приведенной выше — то у тебя спросят, куда именно поставить останов — на все выражение в целом, на filter или на map.

                          Если кто-то этого не умеет — это его проблемы, а не лямбд.

                          • vintage
                            /#10102540

                            Особенное удобство — ставить точки остановка в каждой "лямбде", чтобы можно было пройтись по шагам. Ну или очень внимательно на каждом шаге выбирать между "step into" и "step over", а если ошибся — начинать заново.

                            • areht
                              /#10102890 / +1

                              Так у вас претензии к лямбдам, к fluent, или их к поддержке IDE/VM?

                              Вы пользовались IntelliTrace? Оно решает проблему с «на каждом шаге выбирать между „step into“ и „step over“, а если ошибся — начинать заново».

                              • vintage
                                /#10102902

                                У меня претензии только к тем, кто пишет код без оглядки на то, как его потом дебажить. Я верю, что для других языков есть всякие крутые инструменты, но в JS если есть возможность использовать циклы и переменные, то лучше использовать циклы и переменные, а не изобретать звездолёт, для которого нужен специальный дебаггер, который изобретут только в следующем году и то, только под одну платформу.

                                • qw1
                                  /#10103012 / +1

                                  Тут имеем выбор

                                  1) Написать понятный код, в терминах задачи, с использованием цепочки filter, reduce и прочих высокоуровневых конструкций (код, который очевиден и не требует дебага),

                                  либо
                                  2) Написать цикл, в котором происходит какая-то обработка. Человек, читающий код, всё равно должен будет прокрутить в уме выполнение кода и привести этот цикл в термины задачи, чтобы понять, что тут делается.

                                  • vintage
                                    /#10103050 / -1

                                    Вы правда считаете первый код "простым, понятным и очевидным"? Боюсь вы один такой, для обычных людей итеративный алгоритм проще, понятней и очевидней рекурсивного.


                                    Вы хотите сказать, что пишите код без ошибок, раз он у вас "дебага не требует"?

                                    • areht
                                      /#10103160 / +1

                                      Вы про это?

                                      const users_by_name = users.reduce( ( index , user )=> {
                                          const name = `${ user.name_first() } ${ user.name_last() }`
                                          return { ...index , [ name ] : user }
                                      } , {} )
                                      

                                      Тут же нет рекурсии (если я правильно понимаю написанное).

                                      Ну и таки лично я подобное пишу без дебага, как
                                      users_by_name = users.ToDictionary(user => user.name_first() + ' ' + user.name_last());
                                      

                                      В JS и с этим проблемы?

                                      • vintage
                                        /#10103186

                                        Тут же нет рекурсии (если я правильно понимаю написанное).

                                        Под капотом, конечно, нет, но описание рекурсивное.


                                        Ну и таки лично я подобное пишу без дебага, как

                                        У массивов нет такого метода. Впрочем, не важно. Требования изменились, теперь надо искать как по имя-фамилия, так и по фамилия-имя. Ваши действия?


                                        Мои будут такими:


                                        const users_by_name = {}
                                        
                                        for( let user of users ) {
                                            const names = [
                                                `${ user.name_first() } ${ user.name_last() }` ,
                                                `${ user.name_last() } ${ user.name_first() }` ,
                                            ]
                                            for( let name of names ) {
                                                users_by_name[ name ] = user
                                            }
                                        }

                                        • areht
                                          /#10103250

                                          users.Single(user => 
                                             user.name_first() + ' ' + user.name_last() == searchterm 
                                          || user.name_last() + ' ' + user.name_first() == searchterm)
                                          


                                          Ну, или ближе к вашему варианту
                                          users.SelectMany(user => new []{
                                          new KeyValuePair(user.name_first() + ' ' + user.name_last(), user),
                                          new KeyValuePair(user.name_last() + ' ' + user.name_first(), user)
                                          }).ToDictionary()
                                          


                                          > но описание рекурсивное.

                                          Не вижу

                                          • qw1
                                            /#10103270

                                            Тут не учтены повторы ключа. Если name_first == name_last, свалится с исключением «An item with the same key has already been added». Нужен Distinct перед ToDictionary

                                          • qw1
                                            /#10103274

                                            Решение с Single не подходит, линейный поиск. Неспроста же требуется построить словарь.

                                            • areht
                                              /#10103316

                                              > Неспроста же требуется построить словарь.

                                              Незнаю-незнаю, удваивать размер словаря и одновременно оптимизировать… Если там следующим шагом отчество комбинаторно добавится — Single может выиграть )

                                              > Если name_first == name_last

                                              А так бывает? )
                                              Проще найти полных тёзок, там и ваш вариант упадёт.

                                              • qw1
                                                /#10103394

                                                А так бывает? )
                                                В тестах бывает )))
                                                найти полных тёзок
                                                По ТЗ, должна быть возможность однозначного поиска человека по ФИО, значит, таких данных нет на входе. Хотя, защитное программирование никто не отменял… С другой стороны, код vintage с циклом будет глючить, выдавая только первого тёзку. Может, лучше бы падал, чтобы привлечь внимание к проблеме.

                                                • vintage
                                                  /#10103408

                                                  Заметьте, что лучше получить эксепшен "пользователь такой-то и такой-то имеют одинаковые имена, что не допустимо по такой-то причине", чем "ой, что-то пошло не так не могу добавить объект абракадабра в какой-то словарь, так как там уже есть какая-то белиберда".

                                                • areht
                                                  /#10103516 / +1

                                                  > По ТЗ, должна быть возможность однозначного поиска человека по ФИО, значит, таких данных нет на входе

                                                  Значит неправильное ТЗ )

                                                  Его не надо реализовывать, надо найти ответственного и вставить выяснить как так получается, что на массиве, где тормозит линейный поиск, нет тёзок.

                                                  • vintage
                                                    /#10103662

                                                    Очень просто: у нас онлайн-игра, где ещё на стадии регистрации отсекаются похожие имена, чтобы игроки не путались.

                                                    • areht
                                                      /#10103868

                                                      Значит нет и проблемы с «name_first == name_last», и нет исключений при построении словаря, ок.

                                                      • qw1
                                                        /#10104526

                                                        Значит, полных тёзок быть в принципе не может.

                                                        Но без учёта случая имя==фамилия, есть проблема, что юзер может уронить приложение, введя некоторые данные )))

                                                        • areht
                                                          /#10104892

                                                          Ввод данных пусть заботит того, кто его пишет

                                                          • qw1
                                                            /#10105762

                                                            А откуда он знает, что реализация следующего сервиса падает, если имя==фамилия. Такая проверка точно его забота?

                                                            • areht
                                                              /#10105806

                                                              Дык, «ещё на стадии регистрации отсекаются похожие имена, чтобы игроки не путались.»

                                                              • qw1
                                                                /#10106914

                                                                Похожие на другие имена, видимо, а не на себя.
                                                                Tom Tom на кого похож?

                                                                • areht
                                                                  /#10107416

                                                                  Давайте ещё раз:
                                                                  1) Это выдуманный пример, который вырос из конкретного кода на JS.
                                                                  2) Этот код на JS не имеет подобных проверок. Совсем.
                                                                  3) Не имеет он их потому, что данные были проверены на стадии регистрации. На этапе регистрации ещё надо решить вопрос обновления нашего словаря-кеша, Tom Tom уронит сначала там, там же уточнятся допустимость имён и, как следствие, правила составления словаря.
                                                                  4) Если вам очень хочется вписать Distinct — я не против, но на большом словаре работу это не ускорит, а мы тут вроде что-то преждевременно оптимизируем. Ради Tom Tom прогонять весь массив через Distinct едва ли правильно.
                                                                  5) Ещё раз, пример выдуманный. В реале это придётся переписать как только клиенту скажут «только имя-фамилия надо писать полностью и с 1 пробелом».
                                                                  6) Да и это всё не важно, тут ТЗ: мой код должен зеркалить код vintage. Вписывать туда проверки, которых нет в исходном коде — вообще не правильно.

                                                                  • qw1
                                                                    /#10107814

                                                                    2) Этот код на JS не имеет подобных проверок. Совсем.
                                                                    3) Не имеет он их потому, что данные были проверены на стадии регистрации.
                                                                    6) Да и это всё не важно, тут ТЗ: мой код должен зеркалить код vintage. Вписывать туда проверки, которых нет в исходном коде — вообще не правильно.

                                                                    В том-то и дело, что исходный пример vintage корректно обработает «Tom Tom». А с парой «John Smith», «John Smith» не упадёт, но с точки зрения логики приложения отработает неверно. Значит, вход с полными тёзками не предусматривался. А «Tom Tom» — допустим.

                                                                    • areht
                                                                      /#10107928

                                                                      Уточню, «зеркалить» — не значит «быть абсолютно идентичным». У него корректно обработает Tom Tom, у меня корректно грохнется на «John Smith». А править код под изменяющиеся задним числом требования я тут не буду.

                                                                      Давайте вы с vintage составите ТЗ, vintage под него напишет корректный код на JS, а потом можно будет обсуждать насколько моя реализация ему не соответствует. Если мне кто-то объяснит зачем.

                                                                      • vintage
                                                                        /#10108032

                                                                        Не, давайте завязывать с этим холиваром :-) Думаю тут уже все высказали всё, что хотели.

                                              • vintage
                                                /#10103400

                                                Обычно индекс вводят когда линейный поиск явно не справляется с объёмами данных. Удвоение размера индекса лишь незначительно замедлит поиск.

                                          • vintage
                                            /#10103380 / +1

                                            Первый вариант, как уже сказали, никуда не годится. Второй — тот ещё ребус. Тут дело даже не в том, как написать по короче. Всегда можно применить специфичную функцию, которая решает твою проблему одной строкой кода. Но поскольку проблем великое множество, то и функций таких в асенале нужно иметь соответствующее число. И не просто иметь, нужно помнить как каждая работает и в каких случаях какую лучше применить. У нас тут было две похожие задачи — вы решили их двумя совершенно разными способами. Можно ещё слегка изменить условия (например, мы хотим получить список всех ключей но только в формате имя-фамилия, без дубликатов пользователей) и вам придётся снова всё переписать с нуля.


                                            И вся эта свистопляска для чего? Потому что кто-то вам сказал, что LINQ — круто, модно, молодёжно. А циклы — удел старпёров и так уже никто не пишет в 2k17?


                                            Не вижу

                                            Присмотритесь:


                                            calc( result => ({ ...result() , [ x ] : 1 }) , {} )

                                            Чтобы понять, что будет на выходе, нужно рекурсивно развернуть result.

                                            • areht
                                              /#10103424

                                              Вам почему то кажется, что «переписать с нуля» — это проблема. Нет, это не циклы, это занимает 10 секунд.


                                              Напомню, что выше у вас проблема была в том, что бы что то дебажить. Мне не надо дебажить ни этот код, ни код qw1, что бы знать как он будет работать.


                                              А в чем «разные» способы? Там только SelectMany добавился для задвоения. В Linq не тысячи функций, а десяток. И при этом qw1 решил ту же задачу другим набором, ничего специфического для задачи там тоже нет.


                                              Простите, но я не вижу проблемы в том, что проблема решается в одну строку кода.

                                              • vintage
                                                /#10103442

                                                Вам почему то кажется, что «переписать с нуля» — это проблема.

                                                Дополнительное время как на написание, так и на проверку эквивалентности старой логики, новые баги, конфликты при мёрже… чур меня, показалось.


                                                Нет, это не циклы, это занимает 10 секунд.

                                                Ухты, 10 секунд. Вы под спидами программируете?


                                                Мне не надо дебажить ни этот код, ни код qw1, что бы знать как он будет работать.

                                                Мне этот простой цикл тоже "не надо дебажить". К сожалению, реальные задачи чуть по сложнее.


                                                А в чем «разные» способы? Там только SelectMany добавился для задвоения.

                                                И пачка new KeyValuePair вместо лямбд.

                                                • areht
                                                  /#10103506

                                                  на проверку эквивалентности старой логики, новые баги, конфликты при мёрже…

                                                  Нет в этой строчке кода ни багов, ни эквивалентности, а конфликтов не больше, чем в циклах.


                                                  К сожалению, реальные задачи чуть по сложнее.

                                                  И там разница между парой строчек и 2 экранами циклов ещё заметнее )


                                                  И пачка new KeyValuePair вместо лямбд.

                                                  Лямбда на месте. Слово KeyValuePair можно выбросить, тогда надо взять старую перегрузку с явным указанием ключа, дело вкуса.


                                                  Мне этот простой цикл тоже "не надо дебажить".

                                                  Напомню, что начинали мы с «Вы хотите сказать, что пишите код без ошибок, раз он у вас "дебага не требует"?». Ну да, придуманные Вами задачи пишутся без ошибок просто потому, что решаются в одну строчку. Где ошибки в JS всплывают я так и не понял.

                                        • qw1
                                          /#10103266

                                          Не знаю js, в c# просто

                                          users_by_name = 
                                            users.Select(x => new {u = x, name = $"{x.name_first} {x.name_last}"})
                                            .Union(users.Select(x => new {u = x, name = $"{x.name_last} {x.name_first}"}))
                                            .ToDictionary(x => x.name, x => x.u);
                                          

                                          • vintage
                                            /#10103306 / +1

                                            Какая длинная… макаронина :-)


                                            Компилятор сможет соптимизировать создание промежуточных объектов до простого засовывания записи в словарь?

                                            • qw1
                                              /#10103378

                                              Теоретически… да ))) Имеет право.
                                              Но практически, я думаю, он оптимизирует только очень небольшое количество случаев, как цепочку filter складывает в один, объединяя условия по AND, или выполняя цикл до первого найденного элемента, если после filter стоит first

                                              • vintage
                                                /#10103412

                                                Подозреваю это даже не какая-то оптимизация компилятора, а обычные ленивые вычисления. То есть filter возвращает не реальный массив, а range над предыдущим.

                                                • qw1
                                                  /#10103556

                                                  С точки зрения библиотеки классов — да, это всё IEnumеrable, но компилятор инлайнит реализации linq-функций, после чего смотрит, что получилось, и оптимизирует.

                                                  Например, проход по массиву с вызовом простой лямбды точно не приводит к вызову функции для каждого элемента. Соответственно, память для хранения переменных, попадающих в замыкание, тоже не выделяется. То есть, оптимизации могут быть весьма сложными.

                        • vintage
                          /#10102520

                          Не знаю, как в вашей среде, но обычно в отладчиках можно выделить часть выражения

                          Это вас не спасёт, когда:


                          1. используется транспайлер и вы смотрите в код через сорсмапы.
                          2. функция окажется не "чистой" и повторный вызов приведёт к совершенно иным последствиям.
                          3. у вас нет доступа к нужным переменным, как на втором скриншоте.

                          Ну и это банально не удобно.

                      • YemSalat
                        /#10104048

                        Вот как тут узнать, что вернул filter?

                        В Chrome Devtools выделяете мышкой, наводите курсор — и он показывает:
                        image

              • ookami_kb
                /#10101652 / +1

                Только вот что-то Ваш второй пример попахивает. В одном цикле у Вас выполняется 2 разных по смыслу действия, это не очень хорошо. Давайте разделим его на 2 отдельных цикла.


                Теперь метод получается довольно длинный, давайте вынесем эти циклы с инициализацией пустого объекта в отдельные функции и будем просто возвращать результат в переменную.


                А потом, чтобы не нарушать принцип DRY, вынесем в отдельную функцию обработку массива, чтобы достаточно было прописать только действие над каждым элементом. И каждый обработанный элемент будем мержить с результатом.


                Черт, кажется, мы только что изобрели reduce...

                • vintage
                  /#10102074

                  В одном цикле у Вас выполняется 2 разных по смыслу действия, это не очень хорошо.

                  Да нет, действие одно — взять user и распихать его по индексам. Какой смысл дважды подряд итерироваться по одной и той же коллекции? Более того, если коллекция генерируется налету, то двойной проход по ней может давать разные объекты со всеми вытекающими.


                  for( let user of User.genegate( 1e6 ) ) {
                      // process user
                  }

                  Тут вам возвращается итератор, который налету создаёт вам объекты. Вы берёте каждый объект и обрабатываете как пожелаете.


                  const users = User.genegate( 1e6 ).toArray()
                  users.reduce( ... )
                  users.reduce( ... )

                  А тут вам необходимо сначала сериализовать итератор в массив, чтобы потом дважды по нему пробежаться, после чего массив выбрасывается (привет, GC).


                  DRY — замечательный принцип, но начиная с определённого порога он приводит к катастрофическому возрастанию Complexity. Поэтому в борьбе с копипастой важно знать меру и не превращать простую строчку кода в ребус.

              • staticlab
                /#10102802

                Строго говоря, код неэквивалентен: в примере с reduce будут создаваться новые экземпляры объектов на каждой итерации. Но согласен, это было сделано с целью демонстрации "императивный vs декларативный стиль".

        • yarric
          /#10102322

          А можно пример, когда замыкания помогают сэкономить на условиях? Как я понимаю, если нужно проверить 10 условий, то так или иначе их придётся вписывать руками.

          • qw1
            /#10102352

            Возможно, вы отвечаете на какой-то другой комментарий, т.к. в этом ничего нет про экономию на условиях.

            • yarric
              /#10105252

              Тогда не совсем понял, зачем в циклах break, continue без условий?


              Так-то семантически что написать map (someArray, someFunc), что написать for x in someArray { someFunc(x) } — большой разницы не видно. До недавнего времени про эти map, reduce вообще никто не вспоминал, кроме функциональщиков.

              • qw1
                /#10105766

                Тогда не совсем понял, зачем в циклах break, continue без условий?
                break — очевидно, поиск первого элемента, удовлетворяющего условию (что заменяется на функциональный first), а continue — применение filter в начале цепочки, в императивном коде способ уменьшить вложенность, замена
                foreach (var x in arr) {
                    if (x < 100) {
                        // обрабатываем x
                    }
                }
                на
                foreach (var x in arr) {
                    if (x >= 100) continue;
                    // обрабатываем x
                }

      • bohdan4ik
        /#10100892 / +1

        1. А с чего вы взяли, что persons приходят с сервера? Какая вообще разница, какой источник данных, если эти данные нужно просто отфильтровать?

        • vintage
          /#10100912 / -1

          У вас есть иное объяснение, почему в качестве имён полей используются буквы "M" и "F" и приходится вводить человекопонятные константы, чтобы с ними работать?

          • VolCh
            /#10101148 / +1

            В базе лежат так, в вёрстке так сделаны select'ы, модуль получения persons писал пенсионер, который с Fortran только слез

    • yarric
      /#10100922 / -1

      map, filter и reduce в стандартную библиотеку Ada не завезли, так что это будет цикл. Всё равно в реальном коде хорошим тоном считается прятать такое в отдельную функцию getPensioners(persons).

      • staticlab
        /#10101086 / +2

        В вашем примере в статье необходимость констант была изящно подменена работой с типами. Здесь подобное может сработать с константами пола. Что тут может предложить Ада? А то ведь "выгодный" синтетический пример можно для любого языка привести.

        • yarric
          /#10101420

          Ну конкретно для вашего примера тип-перечисление (enum) как раз для таких случаев, причём он появился ещё в С.

      • TargetSan
        /#10101692

        Окей, такие вещи, допустим, не везде есть. Но как в Ada с аналогами Iterable/Enumerable/Range для пользовательских типов? И что с передачей функций по ссылке в другие функции? Что с замыканиями и лямбдами?

        • TargetSan
          /#10101710

          EDIT: про наличие subprogram access уже нашёл. Вопрос по лямбдам пока остаётся.

  3. devpony
    /#10100692 / +8

    Я не очень понял, как вы определили операции сложения и вычитания на множестве {1..120}, ведь они не замкнуты на нём. Кольцом вычетов оно тоже не является, так как не содержит нуля. Если операции выводят из множества, то в чём тогда вообще смысл этого типа данных? Чему будет равно a - b, если обе переменных типа Age и равны 120?

    • yarric
      /#10100706 / -5

      Случай равенства a и b в данном примере обрабатывается отдельным условием.

      • devpony
        /#10100850 / +2

        Тем не менее, чему будет равно a - b, если обе переменных типа Age и равны 120? Я не хочу каждый раз писать тонну условий, я хочу, чтобы язык предоставлял удобные и безопасные типы, тем более когда его систему типов так расхваливают.

        • yarric
          /#10100958

          Если убрать условие равенства возрастов и добавить условие ageOfBob <= ageOfMary, то программа скажет Mary is older than Bob by 0 years. В данном случае это странно, поэтому добавлено условие.


          Другое дело — если создать переменную ageDiff : Age и добавить строку ageDiff := abs ageOfBob - ageOfMary, а в блоке exception дописать when others => put_line("Something went wrong!"), то при равенстве ageOfBob и ageOfMary будет генерироваться исключение и результат будет Something went wrong!.

        • alexkunin
          /#10101032

          Я не берусь утверждать, как оно в аде работает, но вообще во многих языках даты (а возраст — это, можно сказать, дата: либо дата рождения, либо дата в летоисчислении от момента рождения человека) и временные интервалы.

          Т.е. «a» и «b» — это числа в диапазоне 1..120 (почему 1, кстати? и почему есть максимум?), а их разница — это целое число, у которого минимум и максимум другие. По смыслу и по свойствам это разные сущности: «возраст» и «разница в возрасте».

          Правда, сомневаюсь, что ада сама выводит этот тип — «разница в возрасте».

    • vintage
      /#10100730 / -5

      А что вас смущает в том, что операция над одними типами возвращает другой? Не знаю как в Аде, но в идеальном ЯП {1..120} - {1..120} должно давать тип {-119..119}.

      • iig
        /#10100754 / +3

        Идеальный язык должен валиться с exception.

        • vintage
          /#10100798 / +1

          С чего бы вдруг?

          • iig
            /#10100864

            Выход за пределы диапазона.

            • vintage
              /#10100906

              Так исходные переменные никто и не меняет — они за пределы диапазона не выходят. А вот разность двух чисел, очевидно, имеет совершенно другой диапазон. Если бросать исключение при любых операциях над числами из ограниченных диапазонов, то какой смысл вообще использовать ограниченные диапазоны? Какой смысл от чисел, над которыми нельзя производить никакие операции, так как почти любая операция даёт числа из другого диапазона? А вот от автоматического выведения диапазонов — пользы предостаточно. Компилятор может обнаружить недостижимость веток кода, переполнение максимального числового диапазона, не учёт некоторых комбинаций условий.

              • devpony
                /#10100998 / +2

                Всё зависит от того, какое подмножество взять и как определить на нём разность. Если, например, взять множество {0..n}, а разность определить как разность по модулю, получим кольцо вычетов — красивую и полезную на практике структуру.

                • yarric
                  /#10101438

                  Можно определить тип


                  type R is mod 10;


                  В этом случае сложение чисел этого типа будет происходить по модулю, то есть R(7) + R(8) будет давать 5.

                  • qw1
                    /#10101520 / +2

                    Синтаксический сахарок для очень частных случаев.

                    В общем случае, надо делать перегрузку операторов как в c++, чтобы на каждую арифметическую операцию можно было написать свою логику и свои проверки целостности данных. И операторы прозрачной конвертации, если своему новому типу присваиваем значение системного или другого пользовательского типа (и наоборот).

                    • yarric
                      /#10101552

                      Есть в Ada и перегрузка операторов для типов данных. И перегрузка функций.

              • devpony
                /#10101012

                Или, например, взять все чётные числа {2n | n <- Z} и определить операции сложения и вычитания естественным образом. Получим коммутативное ассоциативное кольцо, чьими свойствами сможем в полной мере пользоваться и знать, что все операции с нашим типом безопасны и не выведут из множества чётных чисел.


                Можно рассмотреть бесконечное множество типов и соответствующих структур, но лишь некоторые из них будут полезны и безопасны на практике. Об этом нужно думать при проектировании системы и с этим должен помогать язык программирования.

                • vintage
                  /#10101024

                  Операции возвращающие значения из того же диапазона будут работать абсолютно одинаково, хоть компилятор будет кидать исключение, хоть выводить новый диапазон (который эквивалентен исходному). Разница будет лишь для операций, для которых выходной диапазон отличается от входного. И вот в этом случае кидать исключение — глупо.

                  • devpony
                    /#10101030

                    Наоборот! Вдруг я ошибся и определённая мной операция выводит за пределы установленного множества? Тогда я хочу получить ошибку компиляции, а не исполнения. Если мои операции намеренно выводят за границы установленного множества, то какой в этом множестве тогда смысл? Я лучше буду просто использовать Integer, или хотя-бы явное приведение типов.

                    • vintage
                      /#10101058 / -1

                      Если вы явно установили выходной диапазон, как в примере выше, то компилятор ругнётся, что задекларированный диапазон не покрывает выведенный. И даже если покрывает, то компилятор всё-равно должен выводить типы, чтобы ловить подобные ошибки:


                      Int a = - persons.length // a has type Int{ -MAX_INT .. 0 }
                      Int b = random( 10 ) // b has type Int{ 0 .. 10 }
                      return a + b >= 10 // compile error: always false

                      • rafuck
                        /#10103290

                        Not always false. Но не думаю, что минус вам влепили за это.

                        • vintage
                          /#10103420

                          Вот видите, вы не заметили ошибки, а компилятор заметил :-) random( 10 ) возвращает значения от 0 до 9 включительно. В комментариях, я, конечно, накосячил.


                          Да мне ещё и карму слили. Хабр — торт :-)

                          • iig
                            /#10107754

                            Int a = - persons.length // a has type Int{ -MAX_INT .. 0 }
                            Int b = random(random( 10 ) ) // компилятор правда знает , чему равен этот диапазон?
                            return a + b >= 10 
                            

                            • vintage
                              /#10108038 / +1

                              Область значения функции он всегда знает:


                              random( n ) is Int[ 0 .. n )
                              random( random( n ) ) is random( Int[ 0 .. n ) ) is Int[ 0 .. random( n ) ) is Int[ 0 .. Int[ 0 .. n ) ) is Int[ 0 .. n )

                              • iig
                                /#10108050

                                А если что-то более сложное, чем встроенная функция? Рекурсивное что-то типа ряда Фибоначчи?

                                • vintage
                                  /#10108066 / +1

                                  При детектировании рекурсии можно возвращать максимально возможный диапазон

                                  • iig
                                    /#10108090

                                    Можно, наверное. А это все ещё про существующую реализацию Ada (автоматическое угадывание диапазонов, и проверка, если угадать удалось. )?

                                    • vintage
                                      /#10108108

                                      Не, я с Ада не знаком, я так, фантазирую на тему.

      • devpony
        /#10100970 / +5

        1) Если мы вводим тип с ограниченным набором значений, мы, скорее всего, делаем это не просто так а с вполне определённой целью: мы хотим, чтобы любая переменная данного типа содержала значения только из заданного интервала. Очевидно, что и операции над такими переменными должны иметь вполне определённый смысл. Иначе зачем вообще вводить собственный тип, ведь можно использовать Integer?


        2) Хорошо, когда тип данных образует некоторую математическую структуру с доказанными свойствами. Тогда производить операции над этим типом становится просто и приятно, а рассуждать о программе — легче. В любом другом случае ограничения становятся искусственными, а свойства — некрасивыми и не очевидными. Это приведёт только к большему числу ошибок.

        • vintage
          /#10101044 / -5

          Очевидно, что и операции над такими переменными должны иметь вполне определённый смысл. Иначе зачем вообще вводить собственный тип, ведь можно использовать Integer?

          Затем, чтобы компилятор нам помогал. Например, если мы складываем два Integer, то компилятор должен ругнуться, так как возможно переполнение, которое мы не предусмотрели. Предусмотреть это можно следующими способами:


          1. Использовать операцию "сложение по модулю" вместо "сложения".
          2. Предварительно проверить, что число меньше половины от MAX_INT.

          if( user_input < MAX_INT / 2 ) {
              // here user_input has type Int{ 0 .. MAX_INT/2 }
              log( user_input + user_input ) // all ok
          } else {
              // here user_input has type Int{ MAX_INT/2 .. MAX_INT }
              log( user_input + user_input ) // compile error: possible integer overflow
          }

          В любом другом случае ограничения становятся искусственными, а свойства — некрасивыми и не очевидными. Это приведёт только к большему числу ошибок.

          Приведите конкретный пример, не будьте голословными.

          • iig
            /#10108076

            Насчёт целочисленного переполнения не понял. Есть места, где переполнение не возникнет никак (итерация по массиву/строке. Там может быть выход за пределы строки, да. ). Если имеет смысл контролировать переполнения в математике — есть библиотеки типа safeint (C++). Зачем делать проверки всего подряд, если можно проверять то, что необходимо?

            • vintage
              /#10108112

              Ну так, при итерации счётчик сравнивается с длинной массива, а значит не может её превысить. Тут никакие дополнительные проверки не нужны.

    • sshikov
      /#10100928 / +1

      Вы еще про операции сравнения забыли. Как работает a < b, тоже далеко не очевидно.

      • yarric
        /#10100968

        Подмножество Age множества целых чисел наследует операции над этим множеством.

        • sshikov
          /#10101078 / +2

          Оно не может их просто так наследовать. Тут уже привели минимум один пример: если из возраста 100 вычесть возраст 120 (оба валидны), получится отрицательное число, которое возрастом не является.

          Так вот — если вы хотели показать, как это круто, иметь в языке вот такие типы, то у вас это прямо скажем не очень пока получилось.

          type Age is range 1… 120;

          А почему собственно 120? Почему это вообще константы? Может ли этот тип быть параметризован другим типом, задающим границы? Что будет, если в операции участвуют Int и Range одновременно?

          Этот пример на сегодня вызывает больше вопросов, чем дает ответов. И это все далеко не тривиальные вопросы по системе типов языка.

          • vintage
            /#10101116 / +1

            Тут уже привели минимум один пример: если из возраста 100 вычесть возраст 120 (оба валидны), получится отрицательное число, которое возрастом не является.

            А с чего вы взяли, что разность возрастов должна являться возрастом? Возрастом кого может являться "разница возрастов"? :-)

            • iig
              /#10101156

              Поэтому для операций с временем используют специальные типы данных. А то возраст как подмножество int без 0 выглядит странно. В пролёте долгожители, новорожденные… Невозможно сравнить возраст 2 пенсионеров, один из которых старше на полгода: обоим по 65, разница 0.
              И специальный тип данных «разница возрастов» не нужен.

              • vintage
                /#10101194 / +1

                Открываем ISO8601 и видим следующие типы:


                1. момент времени (4 марта)
                2. временной период (37 дней)
                3. временной диапазон (с 5 по 27 число)
                4. повторяющийся временной диапазон (каждый день с 5 до 6)

                К "5 марта в 18:00" можно прибавить "1 месяц" и получить "5 апреля в 18:00".

                • iig
                  /#10101252

                  Непонятно написал, сорри. Имелось в виду, что если уж реализован вменяемый тип для времени, то он будет включать и поддержку операции с временем. А не так как в статье.

            • qw1
              /#10101242

              Возрастом кого может являться «разница возрастов»? :-)
              Очевидно, возрастом родителя на момент, когда у него появился ребёнок :)

              • areht
                /#10102298

                Едва ли. Там же целые числа, точность плюс-минус год.

            • netch80
              /#10102314

              В Ada результатом арифметических операций над некоторым типом является «базовый» тип этого типа (для определения вида range 1..120, насколько я помню, это будет Integer), но при присвоении переменной любого ограниченного типа будет выполнена проверка на вхождение в диапазон этого типа.

              Поэтому, например, если мы считаем A1+A2-A3, где все три типа Age, и A1+A2 вылазит за его диапазон, но A1+A2-A3 не вылазит, промежуточная ошибка не будет замечена, но если результат всего выражения будет присвоен AR типа Age и вылезет за 1..120, будет исключение.

              К вопросу о корректности разности возрастов это не относится.

              Чтобы сделать, что разность возрастов была отдельным типом, нужно создать «пакет» в терминах Ada (это лучше всего соответствует «классу» в C++ и аналогах) и для него уже определить function "-". Механизм, таким образом, для этого есть, хоть и громоздкий. Там уже можно определить и все необходимые прочие операции и ограничения этого типа.

              Если исключить возможность явной конверсии своих типов данных в стандартные (как целые), то можно обеспечить и типобезопасность для контроля размерностей (например, не присваивать километры миллиграммам). В смысле этих возможностей Ada не уступает какому-нибудь C++, хотя и выражает свои возможности более громоздко.

              • vintage
                /#10102548

                если мы считаем A1+A2-A3, где все три типа Age, и A1+A2 вылазит за его диапазон, но A1+A2-A3 не вылазит, промежуточная ошибка не будет замечена

                Так это и не ошибка.

          • eao197
            /#10101124

            Тут уже привели минимум один пример: если из возраста 100 вычесть возраст 120 (оба валидны), получится отрицательное число, которое возрастом не является.

            ЕМНИП, вывалится исключение в run-time. Т.е. когда в Ada описывается тип-диапазон, то при работе с экземплярами этого типа в run-time добавляются необходимые проверки, а в compile-time, там где компилятор видит константы, он может выдать предупреждение.

          • drafterleo
            /#10101166

            А почему собственно 120?

            По этому поводу — случай из трудовых будней. В медицинское учреждение, где работаю, недавно установили (за нехилые такие деньги) Лабораторную информационную систему (ЛИС). В ней для каждого анализа (ну, типа, сахар, холестерин, билирубин и т.п.) предусмотрены нормы в зависимости от возраста (чтобы, значит, человек понимал — жить ему или достаточно). Так вот, максимальный возраст, который там можно ввести = 99 (не больше двух циферок). А на днях пришёл дедушка 1916 года рождения и нормы на бланке с его анализами, естественно, не распечатались. Пришлось «скидывать» долгожителю пару годиков, чтобы выдать осмысленный результат.

            Справедливости ради замечу, что ЛИС таки в трудовой процесс вписался достаточно хорошо (хоть и понаписат на 1С) — много чего автоматизирует и по-крупному не лажает. Однако и мелких забавных косячков (удивляющих до изумления программерской безалаберностю) всплывает тоже прилично. Как говорится — се ля ви.

          • netch80
            /#10102336 / +1

            Тут уже привели минимум один пример: если из возраста 100 вычесть возраст 120 (оба валидны), получится отрицательное число, которое возрастом не является.

            Но сравнению это не мешает: если возраст это не отдельный тип со своими операциями, а уточнение Integer, то сравнение выполняется по правилам Integer, и выход разности за допустимые пределы игнорируется. Тем более что сравнение может вылиться, например, в инструкцию SLT процессора стиля MIPS/Risc-V, которая вообще формально ничего не вычитает :)


            А почему собственно 120? Почему это вообще константы? Может ли этот тип быть параметризован другим типом, задающим границы?

            Есть понятие настраиваемых пакетов, которое практически точно соответствует шаблонным классам C++. Собственно, range задаёт такой же настраиваемый пакет, но встроенного определения.


            Что будет, если в операции участвуют Int и Range одновременно?

            В общем случае операции над range-типами исполняются так же, как над их базовым типом, а проверка на диапазон производится уже при присвоении целевой переменной (или можно форсировать конверсией к её типу какой-то части выражения). То есть, пока вы результат никуда не присвоили или не проконвертировали, сумма Integer + range 1..120 будет считаться так же, как сумма двух Integer. Если это 32-битные, то переполнение будет диагностировано по выходу любого промежуточного результата за общеизвестные -2147483648...2147483647. Более узкий диапазон, как уже сказал, будет проверяться, если вы присвоите переменной типа Age или напишете что-то в стиле Age(A1+X) как одну из компонент более сложного выражения.


            Режим с игнорированием всех переполнений (аналогично unsigned в современном C, всей числовой арифметике на стандартных операциях в Java...) возможен с использованием определений типа mod, например mod 2**32 значит 32-битное беззнаковое с заворотом результата (обрезанием до 32 бит). Если нужно считать таким образом, требуется явная конверсия в такой модулярный тип и обратно. Модулярные — только целые без знака.


            Резюмируя, всё это в языке хорошо определено (иначе бы его не приняли для DoD:)), и достаточно оптимально, как для задачи "добиться отсутствия неожиданных эффектов чуть менее, чем везде". Так что Ваши вопросы по системе типов всего лишь требуют внимательного похода в место типа такого.

            • sshikov
              /#10102426

              Я вовсе не хотел сказать, что в Ada все так плохо :)

              Суть моих вопросов была в том, что все не так очевидно, если вдуматься, и накоторые вопросы по системе типов, по их неявному или явному приведению в операциях (а особенно у начинающих) вполне себе напрашиваются. И ответы на них далеко не всегда очевидны.

        • TargetSan
          /#10101666

          У меня к вам вопрос с подвохом. Позволяет ли Ada объявить пользовательский тип, который можно потом "ограничить"?

  4. alesto
    /#10100720 / +8

    То есть люди поторые пишут hello world туториалы молчат у существовании языка Ada?

  5. Umr001
    /#10100924 / -16

    СКОЛЬКО ЖЕ НЕАНДЕРТАЛЬЦЕВ ОКАЗЫВАЕТСЯ ЗДЕСЬ

    • wishnewski
      /#10102808 / +4

      Вопрос задан некорректно. Также вы пропустили вопросительный знак — утверждаю, что их (неандертальцев здесь) намного больше, чем минусов у вашего комментария — практически все!

      В современных неафриканских популяция вида Homo Sapiens содержится в среднем (с вариациями по планете) от ~2% до ~4.5% генов «неандертальского» человека, у всех без исключения людей — в том числе и у вас. Данные примеси не содержатся лишь в ДНК популяций народов Африки, которые и являются единственными «не-неандертальскими», строго говоря — так как неандертальцы обратно в Африку не совались.

  6. DaneSoul
    /#10100948 / +1

    Не согласен с идеей статьи

    1) Не всегда код предполагает все эти проверки и исключения — задача может быть простая и одноразовая — сделали какую-то выборку на ходу, получили данные и больше нам этот код не нужен — под это все тоже тащить кучу встроенных проверок? Даже если мы 100% уверены в наших исходных данных которые УЖЕ прошли это все в другом месте?

    2) Первый пример проверок выше — это стандартный подход, встречающийся во многих языках, изучив его раз, не надо ломать голову при изучении нового языка, что же тут наворотили эдакого и зачем.

    PS: Ада разрабатывалась как язык промышленного применения, где цена ошибки ОЧЕНЬ высока — там подобный подход действительно оправдан. Но использовать его же, например для скриптовых языков? Зачем?

    • yarric
      /#10100984

      Я бы не отказался использовать такой подход хотя бы для экономии собственного времени на отладке и юнит-тестах.

      • bormotov
        /#10101062 / +1

        странно, но я для экономии времени 1-2-5 разовые штуки пишу на питоне, а всё остальное — на скале. Тоже, для экономии времени.

        И конечно, довольно частая ситуация, когда «помнишь, ты писал скриптик, вот нам такое нужно запустить в работу» — берется скрипт на питоне, обзывается «прототип», собираются требования, и новая задача решается на скале.

        Мне чем-то поможет Ада, в которую map/filter не завезли? А еще был (да есть, конечно), Eiffel, тоже хороший язык для разработки программ, где цена ошибки высока.

        • yarric
          /#10101426 / -2

          Мне кажется, что области применения Ada и Python-скриптов как-то не особенно пересекаются. Scala — окей, дело вкуса, хотя по сравнению с Ada её область применения довольно узкая.

          • bormotov
            /#10101540 / +1

            вроде эта ветвь началась с тезиса «экономия времени».

            Ок, значит там, где питон экономит время, Аде точно нечего делать.

            А там, где скала — дело вкуса, но скала не так хорошая в каких-то вещах.
            В каких? Не компилирует код в бинарник, требует jvm?

            Почему вообще сюда влез — про язык Ада слышу давно, и что характерно — ни разу не то, что ни возникало желания «взять и что-то сделать», а даже понимания, мне вот это действительно нужно вот тут?

            Почему вспомнил про Eiffel — однажды удивительно «срослось» — требования задачи, и то, что предлагал язык. И он очень «легко зашел» в той задаче. Правда, это было уже настолько давно, то сейчас бы ни разу не зашел.

            В какие задачи Ада «легко заходит», и вот реально экономит время, по сравнению с современными инструментами? Ответ на такой вопрос был бы гораздо интереснее, чем рассказ, как компилятор ловит всякие тонкие моменты в Hello World.

            • yarric
              /#10101590 / -3

              А есть ли вообще существенные основания говорить, что Scala годится для создания сложных систем и не создаст проблем в будущем? Чем обоснованы синтаксис и семантика этого языка, есть ли средства формальной верификации? Привязка к JVM — уже существенное ограничение, поскольку это не годится для многих встраиваемых систем, микроконтроллеров и просто когда не хочется писать bloatware.


              Ada — несовременный инструмент? Несколько странная точка зрения.

              • bormotov
                /#10101614 / +1

                очень странный ответ. Мне не интересно про скалу, мне инетерсно про Ада.
                И вы, вместо рассказа, чем Ада хороша, спрашиваете у меня про скалу?

                Давайте исходить из того, что я знаю «скала не очень-то», и выбираю чем бы заменить. Расскажите, почему если я заменю скалу на аду, я буду экономить больше времнеи, каких проблем у меня не будет (не важно, есть они сейчас или нет).

                Точка зраения основана на странице в википедии, уж простите, более простого и быстрого источника у меня нет (а вы вот как-то не спешите рассказывать). На этой странице мне больше всего понравился пункт «испытал влияние»:

                ALGOL 68, Pascal, C++ (Ada 95), Smalltalk (Ada 95), Java (Ada 2005), Eiffel (Ada 2012)

                И конечно, «история» — новый стандарт — Ада 2012. Предыдущий Ада 2005.
                Ок, с «несовременный», я ошибался (в 2000 ых Ада совсем пропала из мира вокруг меня, и я даже не подозревал что два стандарта выкатили за это время), давайте выберем слово «не популярный в индустрии».

                В качестве показателя популярности… Вот, есть статья про всякие рейтинги https://habrahabr.ru/company/kingservers/blog/307012/
                там про Ада нет ни слова. Это, конечно, мало что говорит о языке — у всех рейтингов методики странные.

                Так расскажите что на этом языке хорошо пишется?
                Почему, если я возьму этот инструмент, смогу победить конкурентов, которые пишут на яве (эти ваще просто массой давят), скала, котлин, го, С++ в конце концов, а вон еще хаскель медленно, но растет.

                • yarric
                  /#10102046 / -1

                  Статья не является рекламой Ada, Ada не является серебрянной пулей. Хорош или плох язык для какого-то конкретного проекта определяется требованиями к проекту — может быть там вам Pascal будет лучше всего или Assembler…


                  Если судить о дизайне языков по этим рейтингам, то получится, что самые совершенные и продвинутые языки — JavaScript, Java, PHP, Python и C#.

          • sshikov
            /#10102436 / +1

            У Scala — не узкая, а другая. Я бы поспорил, что на сегодня уже. Scala это например Spark, узкая такая область в строне Big Data.

            • yarric
              /#10105270

              Довольно трудно обосновать, зачем вместо Java нужно использовать Scala, поэтому большая часть потенциальной области Scala таки занята Java-ой.

  7. Umr001
    /#10100976 / -23

    Во что превратился хабр. Люди бездумно не прочитав статьи не поняв смысла (возможно эти люди даже не способны понять смысла статьи) начинают комментировать. Вот что значит комменты открыли для всех

    • Bringoff
      /#10101192 / +12

      Вот что значит комменты открыли для всех

      Сказал человек с тремя комментариями, два из которых написаны капсом.

      • Umr001
        /#10101200 / -11

        и?

        • drafterleo
          /#10101202 / +13

          Есть такой механизм психологической защиты (или психологической адаптации — короче, один из способов самообмана), когда человек какие-то качества, отрицаемые в себе, усиленно изобличает в окружающих. Проекция называется. Хрестоматийный пример — «и что ты смотришь на сучок в глазе брата твоего, а бревна в твоем глазе не чувствуешь?» :)

          • Umr001
            /#10101306 / -16

            подозреваю что тебя плюсанули те же самые люди, которые плюсанули коммент Bringoff. А по твоему комменту… Меня то и изобличить не в чем, что плохого в капсе и почему завести новый аккаунт по каким-то причинам стало вдруг плохо?

            • wishnewski
              /#10102028 / +1

              В субботу-то вечером? Ну-ну :)

            • alix_ginger
              /#10102104 / +8

              что плохого в капсе
              Во что превратился хабр.

  8. gryberg
    /#10101228 / +2

    Странная статья, код на аде тоже весьма странен.
    Особенно when others => null

    Я уж молчу про обработку исключений в конце модуля, в Аде вполне есть классический try-catch и пользователю можно говорить об ошибке, не вываливаясь с нулевым кодом возврата из программы.

    • yarric
      /#10101434

      В этом примере появление других исключений маловероятно.


      Не могли бы вы привести пример "классического" блока try-catch на Ada? Вроде бы исключения всегда обрабатываются в отдельном блоке exception.

      • netch80
        /#10102294

        Адовский

        begin
          Work;
        exception
          when X1 =>
             Y1;
        end;
        


        как по мне, ничем, кроме выбора и группировки ключевых слов, не отличается от

        try
          Work;
        catch X1 =>
             Y1;
        end;
        


        А вот то, что исключения в Ada не параметризованы — не переменные, а только типы — сильно усложняет передачу обстоятельств исключения.

        • yarric
          /#10102326 / -1

          Чисто эстетически — гораздо удобнее иметь отдельную секцию exception в конце блока, чем думать, куда вписать этот try (с которого по-хорошему должен начинаться каждый блок) и делать ещё один отступ.

  9. TimsTims
    /#10101432

    const MAX_PERSON_AGE = 120

    Ну зачем же 120. А если кому-то будет 125? 130? Придется программу ведь переписывать) давайте сразу 150-200.

    • yarric
      /#10101436 / +1

      Будет пропатчено в следующей версии ;)

      • http3
        /#10101458

        Будут пачтить каждый год, пока долгожитель не умрет :)
        А как умрет, то назад вернут :)

        • Mingun
          /#10102224

          А на следующий год понадобится аналитика по смертям за предыдущий и накатят патч вновь :)

  10. dplsoft
    /#10101480

    Мне кажется, автор, хоть и косвенно и спорно, но затронул одну важную тенденцию последних лет. На самом деле, имхо, очень плохую тенденцию.

    Звучит она, на мой взгляд как «Больше языков. Аляпистых. Новых. МОДНЫХ. И не важно что будет потом».

    Лично мое впечатление такое, что подавляющее число «создателей новых языков программирования», не имеют серьезного опыта разработки, и вообще подходят к этому делу как к приключению, к блогу, созданию развлечения для фанатов.

    — «Обратная совместимость выпускамых ими версий языков? Зачем, ведь у нас есть новая вкуссная фича, мы впилили ее — вот, смотрите!». А то что вы не сможете перевести свой проект на новую версию потому, что вам надо будет переписывать мегатонны кода — это их уже не волнует.

    «Ну и что! Зато смотрите как у нас бложик с этой фичей красиво обрабатывает тысячи твитов в секунду!» — Ну вот разве не так? Посмотрите на новость о снятии с поддержки руби 1.8 (кажется, поправьте меня). Мол, «грустно, конечно, что снимается с поддержки, прошло 2.5 года с момента выпуска, но эта версия до сих пор используется, потому, что код написанный для руби 1.8 не работает на интерпретаторе версии 2». (Так, или почти дословно.).
    Занавес. Привлекли, поигрались, и кинули.

    Не предупреждают создатели «самых правильных языков» своих «последователей», и о тм, что «язык для быстрого написания прототипов», «динамической типизацией» и «идеально правильным ООП» — на самом деле крайне редко подходит для серьезных задач, больших систем со сложной логикой, и суровых будней поддержки промышленного кода. А может и не могут предупредить, потому, что сами не знают, или не думают что их последователи будут «пихать невпихуемое». А может и знают, но хотят посмотреть что из этого выйдет — ведь не своими деньгами рискуют, а «если что» скажут типа — «Ну наш язык же для быстрого написания прототипов, о чем вы, не надо было конечно так делать».

    В общем статья хоть и «кривоватая», но она о правильной проблеме — будьте осторожны с очередным «самым новым языком». Скорее всего это просто очередная мода.

    И особенно осторожны будьте, пока не увидите проблемы и границы применимости языка, пока язык не найдет свою нишу.

    Как всякий логический и технический инструмент, язык программирования — имеет свою область применения. Применять технический инструмент, не понимая когда этого делать не надо — это чистой воды глупость. Но как раз о недостатках своего детища — в эпоху «рекламы и красивых бложиков» — создатель нового языка, "который, как оказалось, понравился не только ему" — не предупреждает.

    Об этом статья. Имхо.

    • ik62
      /#10101550 / +3

      новые языки появляются потому что к ЯП предъявляется много требований (в том числе противоречивых и неформализуемых), всех их удовлетворить невозможно, писать софт (и языки) сейчас легко и приятно, поэтому почему-бы и не пописать?

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

      • yarric
        /#10101606 / -1

        Простого программиста или среднестатистическую IT-компанию в таких условиях больше всего интересует вопрос, как не впутаться в какую-то модную технологию, которая может через пару лет оказаться на свалке вместе с ними.

        • bormotov
          /#10101624 / +1

          Это вы какие-то страшилки рассказываете.

          Конечно, если мозгов у руководства компании нет — то компания окажется на свалке, но не потому, что ошиблась в ставке на какую-то технологию, а именно потому, что мозгов нет :)

        • d-stream
          /#10101628

          Хотя в реальности зачастую it-компании и продукты в этом плане опережают технологии -)

        • drafterleo
          /#10101640 / +1

          Полагаю, что «простого программиста» и «среднестатистическую IT-компанию» модные технологии занимают не особо, поэтому бояться в этом смысле им по большому счёту нечего. Кстати, ставка на «проверенных лошадок» вовсе не гарантирует многолетнего процветания — в некоторых сферах риск через пару лет оказаться на свалке (проморгав молодого резвого рысака) тоже весьма велик.

      • bormotov
        /#10101622

        В подавляющем большинстве случаев понять не сложно.
        Куда вливают бабло — то и всплывает.

        Кажется, даже на хабре писали, про Оберон и ветку «языков Вирта». То, что тогда происходило — хороший пример того, как бабло вливаемое Sun, IBM, Oracle подняло наверх Java и сопутствующие технологии.

        • ik62
          /#10101638 / +1

          но есть хорошие языки в которые бабло не вливали и они вполне живы.

          • Londoner
            /#10101670

            Это какие же?

            • ik62
              /#10102116

              «хорошие» — понятие субъективное. Что-бы избежать холивара ппредлагаю смотреть в рейтинги языков. Посмотрите в первую десятку любого рейтинга, вы там найдёте пару-тройку языков за которыми не стояли корпорации с вливаниями денег, девелоперов, инфраструктуры.

              • Londoner
                /#10102258 / -1

                Так не пойдёт. Выкладывайте тут ваши десятку и пару-тройку и тогда будем предметно дискутировать.

          • bormotov
            /#10102158

            Эти редкие исключения настолько хороши, что в них вливают «бабло» люди, которые ими пользуются.

            А с какого-то момента срабатывает «количество переходит в качество». Когда закончился хайп вокруг явы? Можно сказать, что он закончился примерно в тот момент, когда перестали вливать бабло. Но к этому времени язык уже набрал массу, и если не стал первым, то был в пятерке популярных инструментов уж точно. С этого момента активные вливания ненужны — все кто поставил на эту технологию вливали по капле.

        • dplsoft
          /#10101840 / +2

          Но я бы, все таки, не ставил знак равно между вливанием бабла и успехом.

          Понятно, что серьезная поддержка требует денег и не малых — я даже не представляю затраты на разработку новой спецификации Java в условиях обеспечения 100% обратной совместимости, или на разработку тестов джавамашины.

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

          Джаве это удалось.

          Я сомневаюсь, что Нуралиев, принимая решения о начале работ над «1С Enterprise Tools», был под чьим то денежным вливанием, когда принимал решение о том, что это будет написано на Java под Eclipse.

          Удалось получить признание Джаваскрипту. даже стандартизирован, развивается.
          Си с Плюсами развиваются тоже без особого жесткого маркетинга.

          Дотнетам — имхо, ещё не факт, что удалось подобное. Пока майкрософт сам пилит продукт, пока платит за шумиху вокруг языка — оно будет жить. Но вот я не вижу пока такого же сообщества какое сложилось вокруг джавы. имхо.

          Имхо, вливание не гарантирует. Хотя и необходимо.

          • bormotov
            /#10102194

            Конечно, там не равенство, но «бабло» — самый весомый коэффициент этой функции.

            Конечно, тупо лить — толку не будет. Что бы лить бабло, тоже нужны мозги. Но в моменты, когда появляются люди начинающие грамотно лить бабло, у функции «эффективный инструмент» меняется характер, если можно так выразиться. Вместо того что бы это был «эффективный инструмент для разработки», делают «эффективный инструмент для бизнеса». Само по себе, это может быть даже и лучше, но просто «разработка ПО» и «бизнес разработки ПО» — таки разные вещи. Акценты в разных местах.

            Отличный пример 1С, просто прекрасный. Давайте крутанём историю, и посмотрим, а что вообще можно было взять когда они начинали готовое? VBA? Была цель, было понимание чего нужно получить в итоге, и были ресурсы. Наверное тогда написать свой интерпретатор было совсем недорого, а плюсы огромные — полная независимость от кого-либо. А сейчас оказалось, что Java и Eclipse выгоднее, и это тоже бизнес-решение.

            История Javascript'а интересная, кто-то может примерно показать момент, когда он начал взлетать? Когда из инструмента «что бы подгружать в фоне картинки» он начал набирать массу. Что происходило? jQuery? Или уже когда Node.js появилось?
            Но в плане JS гораздо интереснее посмотреть на «запрос рынка». Какие стояли задачи, и какие в тот момент были доступные инструменты, было что-то лучше чем JS для решения тех вот задач? «Лучше» по множеству критериев, в первую очередь, по бизнес-критериям, а не по «удобству разработки».

            • areht
              /#10102216

              > История Javascript'а интересная, кто-то может примерно показать момент, когда он начал взлетать?

              Когда Apple сказал, что плагинов c другими языками на iphone не будет.

              • bormotov
                /#10102228

                а потом они подумали, что всё равно фигня получается, дали SDK для Objective C, а теперь вообще продвигают Swift. Я по времени не путаю?

                Тогда еще вопрос — ну вот, Apple «отпустило», но получается пинок JS'у дали настолько хороший, что он уже сам дальше полетел?

                • areht
                  /#10105358 / -1

                  Нет так. Они убили flash/silverlight, с тех пор на клиенте монополия JS

      • dplsoft
        /#10101872 / +3

        Я не согласен с утверждением, что языки появляются потому, что к ЯП предъявляются требования. Далеко не всегда.

        Возьмем историю C#. В следствии каких требований появился этот язык?
        в следствии одного единственного, и не к языку, а вообще: майкрософту нужен был конкурент джаве. Не больше, ни меньше. Им плевать на ваши требования к языку. «Чисто бизнес, ничего личного». Они бы джаву использовали, но в своё время их за попытку создать несовместимую с эталонной реализацию языка джава — жестоко пои… наказали юристы Sun

        Или — в следствии какого требования в Питоне невидимые символы стали использоваться не только как разделители? это не требование к языку, это спорное решение его создателя, попытка навесить на язык функции, ему не свойственные (кслову — неужели, кто то думает, что перейдя с питона на си, люди будут продолжать форматировать код отступами, если они не понимают зачем они это делали, а теперь можно не форматировать? смешно как то...)

        Или вот в следствии каких требований к языку, в руби класс (имя класса? поправьте) можно подменить объектом и поломать создание объектов во всей программе? это не требование к языку обусловленное решаемыми задачами, это желание его автора, воплотить некие идеи о «некой идеальной ооп-шности в вакууме». или вот какие требования к языку обуславливают, что разные реализации руби не совместимы друг сдругом?

        Вот не связаны качества многих новых языков с требованиями, возникшими из задач, которые надо решать. Это решения их создателей, мода, красивый ближик, философия… но не требования к ЯП.

        Языки сегодня создаются как стартапы — не от потребности решить проблему, а от других причин. от бизнесово-коммерческой жилки до банального ЧСВ.

        Сегодня среди живых, распространенных языков, я вижу только 3 которые «возникли от требований к языкам», или сформировались исходя из задач, которые они решают: c/c++, java, javascript. Ну ещё куча ассемблеров под разные процессоры или микроконтроллеры.

        Сишарп похоже начинает воплощаться в нечто похожее на потребное, но как то слишком многь в него впихивают «модностей».
        Для утилитарного рабочего языка нужно далеко не это.

        Практически все откровения про новые языки — выглядят как некие «нечистые манипуляции над неокррепшими умами неосиляторов с/с++» (да простят меня адепты модных языков).

        Потому что когда я слышу объяснения, что вот тут новый язык, и он такой милый/удобный/красивы/удобный язык, в нем «так много синтаксического сахара», или в котором реализован «самый правильный философичный ооп» или «это самый функциональный из функциональных» — я начинаю сильно подозревать, что люди, которым это нравится, не собираются повседневные задачи решать, а собираются играться с логическими задачами из академической среды.

        Я тоже не против почитать про хацкель, под бутылочку пива, дома вечером, но ребята, не на работе же, и не тогда когда нам надо остатки на складах считать и xml-ки валидные прогружать гигатонами! не надо писать на хацкеле учетную систему, не надо на пхп делать модуль обработки веб-сервиса )

        И знаете, мне это напоминает анекдот про байкеров и стрит-рейсеров.
        "- Давайте что ли знакомиться? Мы же тоже на мотоциклах гоняем, только на спортивных.
        — А что с вами знакомиться — вы каждый год новые."

        Каждый год новые откровения про очередную серебрянную пулю, новые языки, новые восторженные юнцы, которые бездумно лезут на новый лад очередного моднявого подобия бездумно все переделать… блин ) Рассказывал знакомый бывший рубист — из 200 рубистов собеседование прошел 1. Алгоритмов не знают, паттернов разработки не знают, структрур и технологий не знают, думать не хотят… зато они знают руби, самый модный язык, для решения всех каких ни попади задач, с высокой зарплатой программистов. Вот эти толпы хомячков и составляют основную массу последователей, как создающих, так и пользующих тысячи новых языков. Прилетающих как мухи на мед. А вы говорите… требования к ЯП… хи).

        Что делать с этим не знаю. Но уж точно не пытаться оправдывать появление десятков новых языков некими «требованиями к ЯП». имхо)

        • 0xd34df00d
          /#10102016 / +1

          Я тоже не против почитать про хацкель, под бутылочку пива, дома вечером, но ребята, не на работе же, и не тогда когда нам надо остатки на складах считать и xml-ки валидные прогружать гигатонами! не надо писать на хацкеле учетную систему, не надо на пхп делать модуль обработки веб-сервиса )

          А, кстати, почему не на хаскеле?

        • vintage
          /#10102084 / +1

          Или — в следствии какого требования в Питоне невидимые символы стали использоваться не только как разделители?

          Требование простое — простота восприятия кода человеком.Фигурные скобки этого не обеспечивают. Отступы — обеспечивают. При наличие отступов, фигурные скобки не несут никакого дополнительного смысла.


          Сегодня среди живых, распространенных языков, я вижу только 3 которые «возникли от требований к языкам», или сформировались исходя из задач, которые они решают: c/c++, java, javascript.

          Вот уж что-что, а JS — всегда развивался стихийно и сильно подвержен модным тенденциям, не обусловленным ничем, кроме хайпа.

          • netch80
            /#10102272

            > При наличие отступов, фигурные скобки не несут никакого дополнительного смысла.

            Есть один случай, когда отсутствие скобок таки вредно влияет на восприятие: это поиск конца блока, не охватываемого одним взглядом, а особенно, когда таких блоков несколько. Что-то вида

                if условие1:
                    ...
                    if условие2:
                        ... тут пара экранов всякого ...
                    #end
                #end
            


            Вот без этих #end увидеть конец блока может быть очень нетривиально.
            Кто-то скажет, что нефиг такие крупные блоки создавать. Я не буду сильно возражать, но случай разный бывает, и код — тоже. (Особенно при отсутствии оптимизатора, который позволил бы вынести действия в отдельную внешне видимую функцию и потом успешно её заинлайнить.)

            В остальном — поддерживаю.

            • vintage
              /#10102574

              Ну и будет как с JSON — лесенка скобочек в середине файла и фиг поймёшь какая к какому блоку относится :-)


              А когда начало блока сверху за границей экрана, а конец снизу за границей, то вообще не понятно с чем ты работаешь. Так что полноценно задача отображения контекста может быть решена лишь на уровне редактора, который бы отображал, на каком уровне какой контекст.

              • herr_kaizer
                /#10102922

                Выбранный уровень лесенки подсветит редактор или IDE. А как подсвечивать ничего в виде отступов?

                • vintage
                  /#10102980 / +1

                  Например, так: https://atom.io/packages/indent-tooltip

                  • herr_kaizer
                    /#10103144

                    Это работает, если блок вмещается в один экран. Иначе придется считать палочки.

                    • vintage
                      /#10103172

                      Присмотритесь внимательнее, что делает этот плагин.

                      • qw1
                        /#10103284

                        Всё равно как-то неинтуитивно.

                        Вот как проблему невидимости заголовка блока решает R# для VS. Он его просто дорисовывает над окном редактора.

                        • vintage
                          /#10103446

                          Чудесное решение. Жаль, что ещё не завезли его в каждый редактор.

                        • drafterleo
                          /#10103474

                          Присоединяюсь, средство, действительно, замечательное (многие редакторы так же перескакивают на парную скобку по «Ctrl + [»). Однако здесь хотелось бы отметить пару моментов:

                          1. Если структурный блок не влазит в экран (а экраны теперь большие), вероятнее всего что-то не так с кодом — желательно подрефакторить;
                          2. Возможно, блок не влазит в экран как раз из-за того, что в нём слишком высокая лесенка закрывающих скобок :)

                          • drafterleo
                            /#10103480

                            P.S. Что примечательно, комбинация « Ctrl + ] / [ » прекрасно работает и в PyCharm — в питоновских блоках.

                          • sergeperovsky
                            /#10109232 / +1

                            Разумеется, очень плохо, когда блок не помещается на экран. Хотя, у кого какой экран.
                            Речь идет о том, что запретить это нельзя. Случаются ситуации, когда приходится писать длинные строки и длинные тексты.
                            Поэтому любой стандарт форматирования имеет смысл, пока способствует удобочитаемости. Но необходимо иметь возможность от него отказаться в тех местах, где его соблюдение ухудшает читаемость кода.
                            Мне очень не хватает в большинстве языков возможности именования блоков. Просто ради того, чтобы осознать назначение некоторых закрывающихся скобок. Делаю это с помощью комментариев, но хотелось бы, чтобы компилятор мог убедиться в правильности вложений.,

                            • drafterleo
                              /#10110228

                              но хотелось бы, чтобы компилятор мог убедиться в правильности вложений

                              По-моему, это уже излишняя перестраховка из серии «бережёного Бог бережёт» (монашка, свечка, презерватив :)). Даже не припомню, чтобы у меня в программах когда-нибудь вылазила ошибка из-за неправильно поставленной блочной скобки. Влепить лишнюю или, там, случайно затереть — такое бывало. Но тогда вообще не компилируется. А чтобы в них запутаться — это, наверное, только с недосыпу возможно.

                • drafterleo
                  /#10103000 / +1

                  В современных редакторах есть такие пимпочки, которые позволяют сворачивать-разворачивать структурные блоки (а некоторые даже вертикальные полоски рисуют, чтобы ненароком не прокосоглазить :))

              • netch80
                /#10103644

                Ну и будет как с JSON — лесенка скобочек в середине файла и фиг поймёшь какая к какому блоку относится :-)

                JSON не позволяет, к сожалению, ставить комментарии. Но само наличие {} скобок позволяет использовать '%' для перехода с начала на конец блока и обратно — это очень помогает в подобных случаях.


                Для аналогичной функции в indent-based синтаксисе есть, например, vim-indentwise. Но с ним, если не ставить эти #end, а есть несколько вложенных блоков, после перехода на конец блока нельзя вернуться на начало блока, возврат будет неоднозначен.


                А когда начало блока сверху за границей экрана, а конец снизу за границей, то вообще не понятно с чем ты работаешь.

                Да, внутри блока это может быть сложно понять. В некоторых IDE (навскидку не помню) я видел показ этой позиции в заголовке окна (не так, как ниже на скриншоте, а в виде пути пакет-класс-функция).

          • rraderio
            /#10105272

            При наличие отступов, фигурные скобки не несут никакого дополнительного смысла.

            А как-же проблемы при Copy+Paste?

        • ik62
          /#10102150 / +2

          Про C# не скажу, не в курсе. В любом случае не верю что у создателей языка в ТЗ мог быть только один пункт — создать конкурента Java. Этого просто не может быть.

          Про хаскель, питон — эти языки создавались с очень четкими ориентирами и выбором компромиссов.
          Сравните характеристики языков (они почти не пересекаются) и вам будет легко распознать что здесь хаскель, а что питон:

          В качестве основных характеристик языка ХХХХХХХ можно выделить следующие:

          недопустимость побочных эффектов (чистота языка); возможность писать программы с побочными эффектами без нарушения парадигмы функционального программирования с помощью монад;
          статическая сильная полная типизация с автоматическим выведением типов, основанная на типизации Хиндли — Милнера;
          функции высшего порядка, в том числе лямбда-абстракции;
          частичное применение;
          ленивые вычисления (lazy evaluation);
          сопоставление с образцом (англ. pattern matching), функциональные образцы, охраняющие выражения (guards);
          параметрический полиморфизм и его объедение с ad hoc полиморфизмом в единую модель посредством классов типов;
          алгебраические типы данных, в том числе псевдобесконечные (за счёт ленивости);
          генераторы списков (list comprehensions);
          возможность интеграции с программами, реализованными на императивных языках программирования посредством открытых интерфейсов (стандартное расширение языка Foreign Function Interface (англ.)русск.[8]).

          и
          YYYYYYYYY is a clear and powerful object-oriented programming language, comparable to Perl, Ruby, Scheme, or Java.

          Some of YYYYYYYY's notable features:

          Uses an elegant syntax, making the programs you write easier to read.
          Is an easy-to-use language that makes it simple to get your program working. This makes YYYYYYYY ideal for prototype development and other ad-hoc programming tasks, without compromising maintainability.
          Comes with a large standard library that supports many common programming tasks such as connecting to web servers, searching text with regular expressions, reading and modifying files.
          YYYYYYYYY's interactive mode makes it easy to test short snippets of code. There's also a bundled development environment called IDLE.
          Is easily extended by adding new modules implemented in a compiled language such as C or C++.
          Can also be embedded into an application to provide a programmable interface.
          Runs anywhere, including Mac OS X, Windows, Linux, and Unix.
          Is free software in two senses. It doesn't cost anything to download or use YYYYYYYY, or to include it in your application. YYYYYYYYY can also be freely modified and re-distributed, because while the language is copyrighted it's available under an open source license.


          Если вы спросите — «зачем нужны эти странные разнообразные требования», то ответ прост — и люди, и задачи у них разные. Кому-то и бэйсик — язык программирования, а кому-то и хаскель недостаточно чист.

          • yarric
            /#10102350

            Вообще-то dplsoft про это и говорит. Характеристики написаны в духе "хочу лямбды и монады", "хочу как в Java и чтобы всё было легко писать". Хотелось бы по-другому: "согласно опыту разработки нужны фичи X и Y, поскольку они полезны в случаях A и B". Для примера почитайте MISRA C — стандарт, который определяет подмножество языка C для применения в mission-critical проектах. Там перечисляются конкретные требования и обосновывается, зачем они нужны.

            • sergeperovsky
              /#10109236 / +1

              Вы хотите от индустрии научного подхода. Увы.
              Пока будешь семь раз мерить, все уже изрежут.

              • yarric
                /#10110526

                MISRA — вполне индустриальная организция. И Ada тоже создавалась с учётом опыта разработки. Сейчас с языками часто обратная ситуация: язык создан для встраиваемых систем — а его прикручивают к мейнфреймам, или язык создан теоретиками, а его пытаются в продакшн.

        • bormotov
          /#10102220

          про форматирование, — отлично. Современная наука software ingenering показывает, что единый coding style — выгодно с точки зрения бизнеса. Есть экономия, которая на больших объемах выливается в заметные деньги. Перенос этого момента на уровень языка, может быть и спорный шаг, но он не противоречит бизнес-целям. Возьмите любой популярный ныне инструмент, у всех есть те или иные средства форматирования исходников к единому виду.

          • 0xd34df00d
            /#10103500

            Я с вами полностью согласен, но ради будущих холиваров с коллегами, на что можно было бы предметно сослаться по части показывающей выгодность единого стиля науки?

            • bormotov
              /#10105426

              Для меня это, как «солнце встает на востоке», но отличный вопрос, некоторым людям нужен пруфлинк, иначе они не воспринимают, даже очевидные вещи.

              Первое, что я сделал — погуглил «why styleguide matter». Но из более-менее общего сходу вылезла только статья https://www.smashingmagazine.com/2012/10/why-coding-style-matters/
              на какое-то исследование не тянет совсем. Еще вылезли пачки готовых style guide, на очень много какие вещи.
              Но самоеудивтельное для меня оказалось статья в википедии https://en.wikipedia.org/wiki/Style_guide
              если точнее, кот этот абзац:

              A style guide establishes and enforces style to improve communication. To do that, it ensures consistency within a document and across multiple documents and enforces best practice in usage and in language composition, visual composition, orthography and typography. For academic and technical documents, a guide may also enforce the best practice in ethics (such as authorship, research ethics, and disclosure), pedagogy (such as exposition and clarity), and compliance (technical and regulatory).


              еще интерсная цитата нашлась в PEP-8 питоновском:
              Donald Knuth explains the traditional rule in his Computers and Typesetting series: «Although formulas within a paragraph always break after binary operations and relations, displayed formulas always break before binary operations»
              со ссылкой Donald Knuth's The TeXBook, pages 195 and 196.

              Дальше — больше! нашелся документ 1995 года, с такими словами
              The classic text on programming style remains Kernighan and Plauger The Elements of Programing Style (1974)

              И к этой книге нашлась интересная аннотация (и небольшой обзор), которая начинается со слов
              This book written by Brian W. Kernighan and P. J. Plauger is one of the first studies of programming style. It advocates the notion that computer programs should be written not so much to satisfy the compiler or personal programming «style», but also should strive for general «readability» and «understandability» by humans with the specific goal to make software maintenance easier.


              вот еще статья, но опять-таки, не научная, без цифр
              http://www.perlmonks.org/?node_id=776607

              А еще нашлась ссылка на McConnel, «Code Complete», которая тоже просто книга, а не научный труд. Но там в PDF'е 897 страниц, из них последние 30 — ссылки на источники. Есть ссылка в том числе и на «The Elements of Programming Style», и например, на

              Woodfield, S. N., H. E. Dunsmore, and V. Y. Shen. 1981. «The Effect of
              Modularization and Comments on Program Comprehension.» Proceedings of the Fifth
              International Conference on Software Engineering, March 1981, 215–23

              туда ссылается вот такой текст:

              Woodfield, Dunsmore, and Shen conducted a study in which
              graduate and senior undergraduate computer-science students
              answered questions about two programs: one that was divided into
              eight routines along functional lines, and one that was divided into
              eight abstract-data-type routines (1981). Students using the
              abstract-data-type program scored over 30 percent higher than
              students using the functional version.

              Конечно, это не только про форматирование текста исходника…

              Думаю, коллег, которым именно нужен пруфлинк, можно смело отсылать в «Code Complete», и далее по ссылкам.

              p.s. Нет, я не знаю как научно обосновать, что солнце встает на востоке

              • 0xd34df00d
                /#10105990

                Спасибо за ссылки!


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

                • bormotov
                  /#10106024

                  Как только в проекте работает людей больше чем один, важно, что бы они не просто были каждый счастлив, а двигались в одну сторону.

                  Посмотрите по ссылкам, везде разговор о стиле начинается со слов «общий стиль облегчает общение». Чем больше людей, тем важность «двигались в одну сторону» сильнее перевешивает важность личного счастья каждого, потому что количество общения внутри коллектива растет экспоненциально. И явного, и неявного — через написание-чтение кода.

                  Нет, я не верю, в сферических коней в вакууме, и в то, что солнце встает на западе.

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

                  Для бизнеса выгоднее подавлять «собственный стиль» даже выраженный в алгоритмах и архитектуре. Единственный практический способ не подавлять — «взваливать» на такого человека «всех остальных», что бы он всех тянул. Но это равнозначно тому, что у всем остальным насаждать его стиль. Иначе, если код понятен только одному человеку, то фактически один человек работает. А нужно, что бы десяток или несколько десятков.

                  Это же простая арифметика: если написать код красиво у «художника» занимает 5 минут, а потом у десятка «маляров», чтение кода вместо 5 минут занимает 30, то бизнес теряет 250 минут. Если «художник» потратит 30 минут на написание кода, который «маляр» поймет за 5 минут, то потери будут всего 25 минут (плюс, конечно, личное несчастье, и неудовлетворенность «художника»). А что бы бизнес ничего не терял — разрыв нужно сокращать.

                  Внезапно, единый стиль оформления исходника — это первый шаг к сокращению разрыва, к увеличению эффективности общения в команде. Как только команда начинает говорить на «одном языке», начинает сокращаться разрыв между «художником» и «малярами» по остальным пунктам.

                  • vintage
                    /#10106036

                    Учитывайте ещё, что время художника стоит гораздо больше времени маляра.


                    А так, не стоит смешивать в одну кучу атипаттерны типа "всё в одну строку и фиг разберёшься" и вкусовщину типа "ай, пробел не с той стороны, дизлайк, отписка". Нужно всё же вырабатывать в себе толерантность к чужому коду, чтобы не испытывать потом боль и страдания, при переходе в другой проект, с другими правилами расстановки пробелов.

                    • bormotov
                      /#10106086

                      Конечно художник в единицу времени приносит больше ценности бизнесу. Но если он за дополнительные 25 минут сможет заменить 250 часов работы маляров — зачем тогда маляры?

                      О какой толерантности может идти речь, если яркие личности со своим стилем становятся счастливее и работают эффективнее? (на минутку стал на другую сторону)

                      На мой взгляд, единый стиль — это и есть та самая середина, которая не вызывает боль и страдания ни у кого в команде, к которой все как минимум толерантны, и соблюдение которой не снижает персональную эффективность.

                      И хочу акцентировать — в общем случае стиль затрагивает не только в форматировании исходников.

                      • vintage
                        /#10106564

                        Боль, страдание и шизофрению вызывает необходимость придерживаться разных стилей, работая в разных проектах попеременно. Поэтому вместо того, чтобы заставлять всех писать как один, лучше учиться читать, не обращая внимания на несущественные особенности. А то доходит до смешного — некоторые не могут прочитать JS код пока не расставят точки с запятой в конце каждой строки.

                        • bormotov
                          /#10106734

                          У нас в рамках компании один стиль. Сколько бы проектов не было.

                          не обращая внимания на несущественные особенности

                          Вы считаете, что мои слова «стиль затрагивает не только форматирвание» — это несущественные особенности, и не обращаете на них внимание?

                          Есть еще интересный факт — умение читать разные стили, совсем не избавляет от требования писать в рамках одного проекта в одном стиле (который принят в этом проекте). Даже не касаясь производительности и бизнес-показателей — это элементарное уважение к коллегам.

                          Точки с запятой в конце строк — смешно, а вот, скажем, алиасы таблиц в sql-запросах, единый подход к выбору имен идентификаторов — тоже смешно? Идем дальше — единый порядок аргументов функций для API?

                          Вот, из недавного, что меня удивляло: модуль, который дает удобные методы работы с целым пластом данных. Среди них всякие выборки/срезы. Среди них — есть срезы по времени. Для меня очевидно, что если функция принимает аргументы date_start, date_end, то у всех функций с аналогичной семантикой в этом модуле (а лучше, во всём проекте), если есть два таких аргумента, они как минимум должны называться одинаково.
                          А еще, например, в Oracle PL/SQL, нет удобного способа вернуть курсор с данными поэтому у процедур из которых нужно возвращать данные, последний аргумент что-то типа P_RC IN OUT REF_CURSOR.
                          Хорошее требование, всегда этому аргументу давать одинаковое имя? Или RC, RC1, P_RC, P_RC1, P_CURS, CUR — нормально, все ведь прочтут, все натренировали толерантность и не испытывают боль?

                          Пример с RC/итд из реального исходника -
                           grep "OPEN .* FOR" some_source.pkg
                          
                          — 91 штука всего, 6 разных вариантов, преобладает P_RC.

                          • vintage
                            /#10108010

                            А у нас много компаний, и каждая устанавливает свои требования.


                            Хорошие примеры и все их можно обосновать как "хорошие практики". Поэтому я и написал:


                            не стоит смешивать в одну кучу атипаттерны типа "всё в одну строку и фиг разберёшься" и вкусовщину типа "ай, пробел не с той стороны, дизлайк, отписка".

                            К сожалению, хорошие практики довольно плохо поддаются линтингу в отличие от поверхностной вкусовщины.

                • sergeperovsky
                  /#10109300 / +2

                  Пока программист не осознАет, что пишет не только ( и не столько) для компилятора, но и для других программистов, которым придется изучать и модифицировать его текст, его нельзя брать в серьезную разработку.
                  Конструкторов «с детства» учат соблюдать ЕСКД. Проектировщиков-строителей ЕСПД. Зачем? Чтобы ЛЮДИ легко друг друга понимали.
                  Программы типа «Hello, World!» плохи тем, что скрывают эту сторону вопроса. Написал, запустил, работает. Просто и понятно. Буду программистом.

      • yarric
        /#10102262

        Было бы хорошо, если бы новые языки действительно предлагали какие-то новые подходы к решению задач программирования. А поскольку какие-то новые подходы придумать трудно, то в большинстве случаев "новый" язык — это просто случайная смесь фич Java, Haskell, Ada, C++, LISP и т. д. по вкусу авторов, в итоге вместо программирования приходится тратить время на изучение взглядов автора на схему наименования стандартных библиотечных функций, указателей на собственный и родительский класс и названия стандартных типов данных.

    • alexeikh
      /#10101852 / +1

      В целом с комментом согласен, но наезд на Руби не в тему.

      Руби 1.8 вышел в 2003 году, а Руби 2.0 в 2013. Так что с «2.5 года» вы как-то погорячились. И уж не помню, что там сломали в 2.0, но помню, что весь старый код, который я пробовал с новой версией интерпретатора, продолжал работать. Не спорю, что какие-то мелочи может и сломали, но, читая вас, создаётся впечатление, что прям вообще всё сломали и на новой версии даже и пытаться не стоит запускать старый код. Это, конечно, не так.

      Выберите лучше другой пример. И проверьте его на достоверность. Или не приводите вообще.

      • dplsoft
        /#10101878

        http://citforum.ru/news/30515/

        ну я же говорил, что меня надо поправить:
        * не 1.8, а 1.8.7
        * не 2.0 а «1.9.3, которую постепенно вытеснит ветка Ruby 2.0».
        * не 2.5 года, а почти 5 лет.
        так, что это не наезд, а констатация типовых проблем. это мы еще дотнет 3.5 и дотнет4 не обсуждали.

        весь старый код, который я пробовал с новой версией интерпретатора, продолжал работать.
        вам крупно повезло, имхо. а большой ли был проект, сколько человек и как долго писали, часто ли перерабатывали?

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

        • khanid
          /#10102268

          дотнет 3.5

          Не знаю, как у программистов, но вот этот 3.5 — головная боль администраторов.

    • Mingun
      /#10102240

      Все-таки наезд на обратную совместимость необоснован. В современном мире это должно делаться автоматическим рефакторингом. В конце концов, если проект развивается, то он должен следовать в общей канве, а не отдаляться от нее, иначе через какое-то время его просто некому будет развивать. Если не развивается, то какая вам разница, что там поломали в версии Y? Пользуйтесь версией X

      • dplsoft
        /#10103482

        В современном мире это должно делаться автоматическим рефакторингом.
        Эээ… а что вы имеете в виду под «автоматическим рефакторингом» в контексте языков с динамической типизацией? руби же, кажется, язык с динамической типизаицей?

        Как уже было упомянуто, нет методов провести автоматический рефакторинг кода для языка с динамической типизацией — потому, что вы не можете узнать, что именно вам подсунут в значение переменной до момента рантайма и сработает у вас обращение к измененному методу или нет. Это не говоря о ситуации, когда у вас функция вызывается в нескольких местах, и вам подсовывают разные типы в один параметр.

        Весь рефакторинг кода при динамической типизации — это смесь ручного труда и обработки баг-репортов после того как у вас не прошел очередной тест.

        А когда у вас большой продукт — ручной рефакторинг с масштабным тестрованием — это ОЧЕНЬ серьезная проблема. Иногда даже проще написать продукт с нуля. На языках со статической типизацией. джаве/сиДиезе/паскале/сиПлюсПлюс — там, где автоматический рефакторинг возможен.

        Если не развивается, то какая вам разница, что там поломали в версии Y? Пользуйтесь версией X
        «Нельзя пользоваться версией X, потому что она снимается с поддержки» => никаких исправлений ошбок, заплаток для безопасности, никакой линии техподдержки и ответов производителя по вашим багам.

  11. MrGobus
    /#10101948

    Ахаха, забавная статья про «Hello World» в которой ни разу не используется фраза «Hello World». Прямо «Hello World» а 0 байт =)

  12. Dessloch
    /#10102032

    А по-моему авторы «Hello, World» правы:

    a=""
    a=''
    a=120
    a=120.0
    

    и нет необходимости в дополнительных string, char, integer, double.

    • netch80
      /#10102256

      А почему Вы решили, что 120.0 будет обязательно double? Может, это single («float» в C и потомках). А может, вообще должно быть тут десятично точное значение и применена десятичная арифметика, чтобы никакие 1.1 не надо было округлять в мелких знаках.

      120 — почему integer, а не short или long? И даже почему не double?

      На примере констант это всё не видно, но как только начинаются реальные операции с данными, тип вдруг начинает иметь значение.

      • masai
        /#10102682

        Скажем, в C литерал 120 — это точно int, а 120.0 — точно double.

        • netch80
          /#10103862

          Скажем, в C литерал 120 — это точно int

          120 — да. 120000, например, уже не обязательно. В C99, например, сказано следующими словами:


          The type of an integer constant is the first of the corresponding list in which its value can be represented.

          Если на платформе int 16-битный, 120000 автоматически станет long.


          Но тип константы тут не так важен. Важнее то, что будет, если мы обопрёмся на это вычисление типа при назначении его переменной, и значение потом будет меняться, а тип — нет. Например, если кто-то захочет опереться на то, что в Java или Go целочисленная арифметика всегда урезает до последних N бит, даже знаковые, и у него тип переменной всегда окажется int64 вместо int32, результаты будут неожиданными. Или в C# написать 2.5 вместо 2.5m; многим такое очень тяжело распознать, даже вглядываясь в код.


          Поэтому автоматическое определение типа хорошо, если далее значение переменной не заменяется. "Внутреннее" изменение может быть; есть случаи, когда автоопределение удобно и при изменении — например, итераторы. Но даже "x += 1" уже даёт стрёмный вариант (а что, если это оказался float более чем 2**24 по модулю?), лучше избегать автоопределения и задавать тип явно.
          (Хм, тут исключений больше. Например, стандартная арифметика над float?ами может адекватно работать при любом их типе. Но это опять же не общий принцип.)

    • yarric
      /#10102366 / +4

      Самое весёлое начинается тогда, когда нужно передать значение в функцию, а функция даже не декларирует, какого типа значение ей нужно (типы-то нигде не указаны). То ли функции нужна строка-имя файла, то ли открытый поток ввода-вывода — иди, читай доки или исходный код. И так каждый раз.

    • sergeperovsky
      /#10109318

      Все зависит от цели.
      Одна команда написала систему анализа движения воздуха методом конечных объемов.
      Как в большинстве вычислительных задач, алгоритм и тип данных оптимизирован под скорость работы.
      Встал вопрос о точности результатов. Я предложил использовать вместо double новый тип «физическая величина» из двух double — «значение» и «погрешность». И заменить стандартную арифметику на принятую в физике: при сложении и вычитании погрешности складываются, при умножении и делении подсчитываются соответствующим образом.
      Работать будет гораздо медленнее, но для исследования применимости расчетов к различным задачам очень удобно.
      Вроде бы, задача не много сложнее рефакторинга. Но программисты дружно отвергли идею — слишком сложно в реализации и отладке.
      Интересно, в каком языке такое изменение не вызовет сложностей?

      • vintage
        /#10109562

        В любом, поддерживющем алиасы типов и перегрузку операторов.

        • 0xd34df00d
          /#10112288

          C++ в ваших терминах поддерживает алиасы типов?

          • vintage
            /#10112424 / +2

            Ну да. Только алиасы надо сразу использовать. Впрочем, поменять везде типы — не ахти сложности задача.

  13. khrundel
    /#10105278 / +1

    На самом деле тип данных «целое в интервале» не является чем-то принципиально недостижимым в других языках. В том же C++ можно сделать шаблон с целочисленными параметрами и реализовать операторы, возвращающие обычный int и имплицитный конструктор из инта, бросающий исключение в случае не попадания в диапазон. Был бы

    typedef IntOfRange<1,120> Age;
    и дальше то же самое.
    Но я не замечал активной работы в этом направлении. Видимо, идея не то что бы полезная, так как варианты с несколькими значениями лучше реализуются перечислениями, а там где действительно нужно число, но не любое, ограничения обычно более сложные, по типу «индекс меньше или равен длине» или хотя бы «только чётные», так что валидацию делают внутри более сложного типа.

  14. alexBondar
    /#10108356

    Не хватает только подписи «Информация прозвучала на правах рекламы продукта Ada… » :)
    А если серьезно, то непонятно в чем мысль статьи. Как по мне здесь «смешались в кучу люди, кони...» — тут тебе и DRY и unit-тестирование и exception handling. Связь с hello world прототипами какая-то очень навязанная.