Comments 327
В вашем примере, безусловно, использование var неуместно:
var unbufOut = NetUtils.getOutputStream(sock);
Но вот пример, в котором ему самое место:
FileOutputStream fos = new FileOutputStream("t.tmp");
В C# так сделано и это удобно.
А мне нравится использовать полные типы в строках вида
SomeClass something = new SomeClass();
потому что после того, как я написал левую половину, автодополнение дописывает за меня правую — мелочь, а приятно.
Наверное надо еще потребовать обязательного явного приведения типов :), чтобы вы писали
Window windows = new
А IDE вставляло еще больше избыточного кода
Window window = (Window) new Window()
В IDE 4 опции:
1) Отображать var v=new T(); как T v=new T();
2) Автоматически преобразовывать var в типы
+ две обратные покроют
все необходимые пожелания всех и каждого.

Другое дело, что почти никто в настройки IDE не полезет, а вот на хабре холиварить будет часы напролет. И да. Я тоже так сделаю ;)
Ну если человек испытывает удовольствие от того, что IDE дописывает избыточный код, который можно вообще не писать, язык должен предоставить ему больше удовольствия — требовать больше тупого дубрирования
Пишите: new SomeClass().var жмякаете таб — ИДЕ генерирует
var something = new SomeClass(); с фокусом на названии переменной которую можете изменить.
Можно даже проще — нажать Ctrl+Alt+V сразу после выражения ("extract variable").
А какой смысл, если вы уже написали левую половину (т.е. само имя класса и имя переменной)? С var вы напишите примерно столько же...
Будет, но выведется конкретный тип ArrayList. Если пытаться выводить до интерфейсов, то так можно дойти до вывода в Object.
Ну это то понятно. Тем не менее неспроста (канонично) слева пишется List, а справа ArrayList. Т.к. ArrayList — это по сути указывается конкретная реализация контракта. Это было к "var из той же оперы" в основном сказано.
Как часто вам в локальном скопе метода важно сокрытие реализации контракта?
Если метод настолько большой, что это играет роль, то мне кажется, explicit/implicit тут уже не спасёт.
Как часто вам в локальном скопе метода важно сокрытие реализации контракта?
В локально скопе — не так уж часто. Я потому и написал про «канонично». Но я лично всегда так пишу и считаю хорошим тоном.
Если вы используете IntelliJ то вы делаете это неправильно — сначало нужно писать правую часть, нажать alt enter и enter(первый пункт всплывающего меню будет — introduce local variable).
Согласен тем, что при простом вызове конструктора проще использовать var. Ведь если писать полное имя типа в объявлении переменной IntelliSence всё равно будет подсказывать с нуля и придётся половину имени типа набирать.
Если вспомнить, то var появился в C# 3.0 вместе с лямбдами и LINQ. И первую очередь он нужен именно там, чтобы не писать моструозные конструкции вроде: IEnumerable result =…
В C++11 auto в целом тоже для тех же целей добавили (с ужасом смотрю на все эти шаблонные итераторы).
Нет. var в первую очередь нужен для работы с анонимными типами, к-ые логично появляются в LINQ при операции проекции (Select)
Да, согласен. Про проецирование я что-то забыл. В этом случае уже без var даже написать полное имя типа нельзя. Не знаю есть ли такое в Java, но с var может и оно появится )
Да, пожалуй случай когда NetUtils возвращает FileOutputStream это действительно весьма странный кейс, когда было бы неплохо увидеть, что тип переменной таки FileOutputStream.
Но вообще для меня видится довольно странным заявление, что var приносит мало пользы и больше вреда. Это где-то аналогичное тому, что говорить что понижение типа это вредно (типа так: OutputStream unbufOut = NetUtils.getOutputStream(sock);). Зависит от случая к случаю.
Вообще, в строке приведенной автором для примера я вижу две проблемы корректного именования и проблему того, что зачем-то метод возвращает максимально специфичный класс. Видать джависты не умеют в корректный нейминг и ООП.
Но вообще для меня видится довольно странным заявление, что var приносит мало пользы и больше вреда.

В статье написано:
Пользы мало, вреда мало.
Когда я вижу такое:
var unbufOut = NetUtils.getOutputStream(sock);
То мне не очень надо знать, какой именно тип представляет обой unbufOut (кстати, обясните, пожалуйста, кто дал такое имя переменной и какомй naming convention оно следует).
Я уже вижу что это именно stream, скорее всего полученный по сокету. Для общего понимания алгоритма это должно быть не важно. Если мне понадобится знать тип, я просто наведу курсор на переменную.
А если мне понадобится знать, что именно делает getOutputStream, я нажму f12 и не потребую к каждому вызову метода приписывать полный текст его реализации прямо в исходнике.
Если мне понадобится знать тип, я просто наведу курсор на переменную.
А если мне понадобится знать, что именно делает getOutputStream, я нажму f12 и не потребую к каждому вызову метода приписывать полный текст его реализации прямо в исходнике.

ТО есть часть статьи про "много работы ведется вне IDE" — вы проигнорировали.
Я вот на днях закончил работу по протированию на Андроид 44 плагинов для проекта с исходниками примерно на 600 файлов. Все из которых я вынужден был редактировать в Notepad++ в силу специфики рабочего окружения.
Куда мне в Notepad++ навести мышку чтобы узнать тип и где нажимать F12?
Тогда да, вам нужно объявлять типы (вместо наведения мышки) и рядом каждым вызовом функции писать ее полный текст в комментах (вместо F12).
А что за особенности окружения?
"Мне" надо?
Неужели вы думаете, что программисты только со своим кодом работают?
А это не только к вам вопрос, на самом деле.
Минусующих меня за утверждение, про разработку вне IDE — достаточное количество и под постом что я выше написал и в карме. Так что я делаю вывод, что программистов работающих в идеальном мире где всегда есть IDE "которая подскажет" — больше чем тех, кто с реальными проектами работает в реальных условиях. :))
Ситуация о которой я ниже писал — это только личный пример и исключение. Но на своей практике я таких исключений уже, наверное, с сотню видел. Когда приходится работать с кодом в некомфортных условиях за пределами такой удобной IDE. И мне странно что есть люди, которые с этим еще не сталкивались...
Особенности окружения:
Плагин испольуземый разработчиками для ведения проекта при сборке и деплое проекта выводит модальное окно, которое блокирует работу с IDE(Видимо чтобы пользователь-идиот не сохранил какой нибудь файл во время сборки не сломал сборку). А еще этот же плагин(чтоб его разработчики в аду горели) при добавлении или удалении файла в проекте инициирует его ПОЛНУЮ пересборку.
Наверно плагин прекрасно себя показал при работе с мелкими проектами… Но когда проект на несколько тысяч строк…
Пока один проект с одним модулем собирается и деплоится — портирование другого ведется в блокноте, чтобы время не терять.
А как от отличает блокнот от IDE? Нельзя ли сделать чтобы плагину не было видно IDE и он его не блокировал? Это плагин для чего?
Можно просто открыть второй инстанс IDE и в нем работать. Благо плагин не блокирует доступ к файлам.
Но по причинам которые я в сообщении ниже написал — это не имеет смысла. IDE все равно кастрированная, и не даст преимущество перед блокнотом.
Плагин — собственно отвечает за сборку и деплой проекта под Андроид.
нельзя ли генерировать проект отдельно для плагина или наоборот из проекта плагина отдельно генерировать проект для IDE? Т.е. отвязать вообще IDE от плагина, как от блокнота.
Думаю что нет. Плагин призван дать возможность писать в MSVS под Андроид и без него студия вообще не умеет Java код понимать.
В целом знакомство мое было с этой системой не долгим и уже закончилось, надеюсь и не возобновится. :)
Так что я не могу ответить на такие вопросы, чтобы еще свежую травму не бередить. :))))
Ах, еще один прекрасный момент этого плагина:
Он не переваривает большие проекты. Поэтому большая часть исходников прописана в мейкфайле, но отсутствует в самой IDE.
Хорошо IDE их хотя бы при дебаге открывает. А так — даже кликнуть по переменной нельзя, чтобы по исходникам побродить. IDE просто не найдет куда перейти.
Можно сказать: не пользуйте странные плагины…
Ну так я и не использую. Заказчик использует. А я работаю с тем, что дают. Как и большинство разработчиков.
Э… И вы хотите чтобы язык приспосабливался к идиотизму вашего заказчика? А если я буду разрабатывать под досом, можно мне ограничение чтобы все файлы были 8.3?
> я вынужден был редактировать в Notepad++
почему это вынужден?
вас ктото заставлял редактировать именно в Notepad++? ваш внутренний голос?
Надо было идти пить чай/кофе. Если такая среда разработки — требование клиента, то и платить за такую радость должен клиент.
Так он и платит.
Я ему не говорил что меня что-то не устраивает и не планирую. Потому что есть работа, есть ее оплата. А комфорт и прочие вещи — это моя проблема, а не клиента.
Это пример вполне рядовой. Обычно всё не так экстремально, но работа с кодом вне IDE — это обычное дело. И это надо учитывать.
Нет, ну если тебе нравится этот геморрой — то пожалуйста. Фишка-то как раз в том, что рынок за программистов (не во всех сферах, но в большинстве существенных). Да и в любом случае — комфорт очень важен при программировании: меньше потенциальных ошибок, лучше погружение в задачу.

Поэтому я предпочитаю использовать особенности рынка для своей пользы — мне вот даже на одномониторной станции некомфортно… Что уж говорить о работе вне IDE… хотя совсем таковая не исключается — различные сниппеты в интернете, код-ревью вне IDE и просмотр коммитов вынуждают пользоваться только подсветкой синтаксиса… но ведь в этом режиме и глубокого погружения, обычно, не требуется.
Еще вопрос, почему можно было установить Notepad++ но нельзя было установить Eclipse ?
> ТО есть часть статьи про «много работы ведется вне IDE» — вы проигнорировали.

Нет, это вы проигнорировали, что это не важно в 146% случаев.

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

Например, если вам нужен тип на ревью — вам не нужен тип, вам нужно джуниору всучить «clean code».
А много ли меняется вне IDE?
Одно только имя типа ничего не дает. Вы все равно видите только тот его интерфейс, который выражен в читаемом коде. Если вам нужно узнать что-то большее — вам придется искать объявление типа по проекту, ведь «не IDE» не умеет переходить к типу, по имени или без него.
Конечно, если есть документация в которой легко находится тип по имени — то тут проще. Но этим же способом можно найти саму функцию, в описании которой скорее всего есть прямая ссылка на возвращаемый тип. Тем более, что если нам неизвестен возвращемый тип, то и остальные знания о функции неплохо бы освежить/получить, так что нам даже по пути.
В итоге, не такая уж большая разница получается, зато пользователям IDE (которых большинство) — профит.
После того, как var разрешат, вы уже не заставите разработчиков явно указывать типы в таких местах (var unbufOut = NetUtils.getOutputStream(sock); )
Более того, на данный момент Решарпер в студии подчеркивает явное объявление типа переменной и предлагает использовать var.
Вот если бы var ввели и разрешили использовать только в случаях, как во втором примере (FileOutputStream fos = new FileOutputStream(«t.tmp»); )
Ну да, египетские скобки в джаве можно заставить не писать, а var нельзя? Точно так же административными мерами решается, через внутренние стайлгайды, в них и пропишете что можно использовать только во втором случае.
Поначалу в C# тоже все плевались и были консервативны.
Потом постепенно начли менять на var ОченьДлинныеИменаКлассов, потом начали менять всё кроме примитивов (int на var не экономит даже буквы), а сейчас все успокоились и полюбили var, вот и в жаве так же будет.
P.S.: в плюсах я тоже везде леплю auto, ибо нефиг ;)
А мне нравится использовать полные типы в C#. Я их даже раскрашиваю разными цветами.
То, что везде пихают — не есть хорошо. И не надо слушать толпу, а то можно сойти на дискуссии про миллионы мух и JavaScript.
ИМХО var, как и auto, уместны только при замене неприличных названий классов для временных переменных. Вроде тех же итераторов, которые на плюсах могут перерождаться во что-то, о чём пишут культисты в своих книгах. В остальных случаях всё же не стоит скатываться в php, да не обидятся на меня адепты синего слоника…
учтите небольшую разницу между php/js и c#/c++: в первых внутри var может оказаться что угодно, во вторых — это вполне конкретный тип, просто мы его не называем.
У меня на работе был случай, когда приложение складывалось по банальной причине: автоматический вывод типа отрабатывал лучше, чем люди. И причина была банальной, в пылу копипасты, как и положено, сделали опечатку. А в итоге вызывалась не та перегрузка метода фабрики и всё, заверте.

Я не спорю с тем, что то был быдлокод, ибо копипаста — не метод, тем не менее ошибки бы не было, если бы вместо «auto type = foo()» был «int type = foo()». И от этого не застрахованы даже лучшие из нас.
Да ладно вам. Типизация от этого никуда не денется, а шума в коде меньше. Доверить веведение типов компилятору — правильная вещь. Вообще, эта фича во многих современных языках. Можно посмотреть на тот же Kotlin, на сколько оно становится компактнее. При чтении кода обычно незачем знать тип каждой переменной, при необходимости всегда можно навести мышкой на переменную и посмотреть тип.
Если вы про

var worker = new MyVeryFreakingAwesomeSuperSlowAndStupidMultithreadAsynchrousSQLWorker.HisCoolResult(kill,this,guy,please);

, то я за. Если вы про

int lososni(int);
byte lososni(byte);
tuna lososni(short);

var item = lososni(1);

, то, пожалуйста, Расмус Лердорф, перелогиньтесь.
Кстати говоря, я очень часто импортирую inner-classes. Вы спокойно можете сделать
import my.superpuperpackage.MyVeryFreakingAwesomeSuperSlowAndStupidMultithreadAsynchrousSQLWorker.HisCoolResult;

...

HisCoolResult worker = new HisCoolResult(kill,this,guy,please);
Чукча не писатель, чукча — читатель. В том смысле, что я перевожу пару проектов с Java на плюсы в свободное от рукоблудства время.
Публичные вложенные классы — дурь последняя. Почти всегда — или нарушение принципов инкапсуляции или неудобный механизм использоваться. И статические импорты таких классов — всего лишь костыль для этого непотребства.
И да, я знаю, что этим болеет и несколько классов в JDK.
На мой взгляд это вполне нормальная группировка классов и интерфейсов по пространствам имён, когда пакет — слишком крупная единица группировки. Это никак не связано с инкапсуляцией. Импорт таких классов не требует слова static, вряд ли его можно назвать «статическим импортом». С точки зрения пользователя такой класс несильно отличается от класса в соответствующем пакете, только имеется напоминание, что он более тесно связан с другими классами в данном окружающем классе.
Ладно, в JDK это могло быть проблемой, но в кастомной библиотеке/приложении вложенные публичные классы какую роль должны играть? С учётом того, что слишком большой пакет — это тоже не очень хорошо (я бы даже сказал — плохо… но с JDK понятно — там сложно было осуществить качественную пакетную детализацию… да при сохранении обратной совместимости).
Вот одна из причин. Если модули (Jigsaw) использовать пока нельзя, толстый пакет удобнее для управления видимостью. Из других пакетов можно использовать только public-методы и классы, тогда как из текущего пакета можно использовать package-private. При разработке библиотек большие куски кода не хочется выставлять наружу, но при этом хочется их переиспользовать в разных частях библиотеки. Поэтому раздутый пакет часто единственная альтернатива. И для дополнительной группировки используются классы. С Java-9 будет легче жить. Эта же проблема, кстати, важна для JDK: у них огромное количество package-private классов (и это очень хорошо), но при этом есть костыли для межпакетного доступа (типа SharedSecrets, это, конечно, плохо).
UFO landed and left these words here
Отсюда и главная претензия к var — риск снижения читабельности

.
Вот! Святые слова! Именно так! Подобные штуки валят дескриптивность кода наповал. Главное, когда я доказываю знакомым плюсовикам, что аналогичная штука в C++ (auto) это зло злющее — они меня не понимают и говорят что это одна из крутейших фич в С++11.
.
Ну ладно плюсы, там есть пятиэтажные жуткие конструкции на шаблонах и итераторах в библиотеках и можно понять желающих скрыть эту жесть. Но Java — язык прикладной, не системный. Зачем?! Так трудно написать тип? Просто лени ради?
.
На мой взгляд var (auto, и все иже с ними) — волшебная палочка в руках ленивого говнокодера, с которой ему теперь даже не нужно утруждать себя обозначать типы. Берегитесь! var превращает карету вашего кода в тыкву нечитабельного ужаса.
.
П.С.: Приношу свои извинения за оффтоп с плюсами, просто накипло.
П.П.С: Что-то странное с разметкой в Хабре — съедаются энтеры (заменил точками в посте). В чём может быть дело?
Сам по себе var может быть удобен, если его использовать правильно и только в случаях когда точно понятно что за тип у переменной. Проблема с ним в том, что его сувать будут куда ни попадя, а там уже сиди и гадай — что ж за тип возвращается в той или иной функции. А если она ещё и интерфейс возвращает вместо конкретного типа…
Лично я не очень его жалую, и не использую обычно, потому что читабельность реально снижается.
Проблема с ним в том, что его сувать будут куда ни попадя

Вот-вот. Мне кажется, синтаксис языка должен быть в чём-то подобен хорошо спроектированной программе — в нём должна быть защита от дурака. Да и просто защита от человека, который прототипирует код. Я сам поддавался греху и использовал эту фичу как проектировал код. Типа: "а, поставлю-ка пока var, пусть будет — там точный тип проставлю". А потом: "так, ладно. Вот var, которому мы присваиваем… var. А, чтоб тебя!"
Так это и начинается :) Я тоже его пробовал использовать. Когда проект пишешь, то мысль "нужен тут var или нет" не является приоритетом, и получается лепишь его везде где можно.
Когда проект пишешь, то мысль «нужен тут var или нет» не является приоритетом, и получается лепишь его везде где можно.

Если с предыдущим вашим постом я согласен, то в данном случае это проблема разработчика, а не самой возможности. Посмотрел в своих проектах использование var:
  1. Тип переменной указан при присвоении(using(var sw = new StreamWriter(path)), т.е. убираем дублирование информации);
  2. Тип переменной известен из имени переменной (cancelButton, аналогично убираем дублирование информации);
  3. При получении промежуточного звена LINQ выражения, если оно будет следом использовано для извлечения требуемых данных (т.е. информация о данном типе не имеет значения, т.к. это короткоживущая переменная, созданная по техническим причинам и используемая 2-3 раза на текущем экране кода).

В итоге VAR позволяет убрать дублирование информации или скрывает ненужную информацию, что не отражается на читаемости кода. Во всех остальных случаях обязательно использование имен типов, а порой и с пространством имен, если важно акцентировать внимание на библиотеку, из который используется данный класс (например, если мы хотим явно указать, что используем NLog в качестве логгера).
Я не противник var вообще, но вот пример из Tox:
public ToxData GetData(string password)
{
       ThrowIfDisposed();

       var data = GetData(); //как выглядят эти самые данные?
       byte[] encrypted = ToxEncryption.EncryptData(data.Bytes, password);

       return ToxData.FromBytes(encrypted);
}

или
var key = salt == null ? ToxEncryption.DeriveKey(passphrase) : ToxEncryption.DeriveKey(passphrase, salt);

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

Именно это я и имел в виду
var key = salt == null? ToxEncryption.DeriveKey(passphrase): ToxEncryption.DeriveKey(passphrase, salt);

А за такое использование я бы точно убил.
Убивать людей не стоит, но автор кода точно хотел написать на Scala с экспрешен семантик :)
А за такое использование я бы точно убил.
Достаточно немного переформатировать код и не будет нужды кого бы то ни было убивать — возвращаемый тип прекрасно виден. Никогда не понимал, почему люди недолюбливают операцию тернарной альтернативы.
var key = (salt == null)
? ToxEncryption.DeriveKey(passphrase)
: ToxEncryption.DeriveKey(passphrase, salt);
Но ведь в данном случае достаточно было указать тип переменной и сразу код бы стал более читаемым, так как уже нет особой нужды смотреть на реализацию. Да и результат DeriveKey не особо понятно какого типа: может строка, а может специальный тип. Но это уже скорее личные придирки.
А в целом это все дела личных предпочтений каждого разработчика.
Я не знаю что такое Tox. Судя по коду приведенный кусок получает откуда-то данные и шифрует. Я ожидаю, что у data скорее ксего тип ToxData
То есть код вида:
NetUtils.getOutputStream(sock).write("hello");

  • вас не смущает, а эквивалентный:

var unbufOut = NetUtils.getOutputStream(sock);
ounbufOut.write("hello");

  • адский ад? Может и первый вариант запретим? Там же не понятно какой тип возвращается! В одной строке должно быть не более одного вызова метода!
Хм… А ведь справедливо. Не задумывался о подобной аналогии с цепочечным вызовом методов. Спасибо, подумаю об этом.
В первом варианте нам не требуется держать в голове контекст, так как возвращаемое значение используется сразу же, по цепочке, во втором же случае — нам нужно помнить тип unbufOut до самого конца области видимости.
В джепе кстати такой же пример в качестве аргумента за:
var path = Path.of(fileName);
var fileStream = new FileInputStream(path);
var bytes = Files.readAllBytes(fileStream);
так и бряки приятнее ставить
Согласен, привязка брейкпоинтов к строкам, а не ленсемам — это боль.
По опыту: если у вас var снижает читаемость, значит у вас гораздо большие проблемы с кодом, чем читаемость.
Проблема скорее не в написании своего кода, а в получении чужого в наследство за три недели до релиза, куда нужно добавить новую фичу
На мой взгляд экзепшоны — волшебная палочка в руках ленивого говнокодера, с которой ему теперь даже не нужно утруждать себя написать и проверить возвращаемое значение.
На мой взгляд функции — волшебная палочка в руках ленивого говнокодера, с которой ему теперь даже не нужно утруждать себя написать ещё одну реализацию сортировки.
Что ж. Вывод из всего случившегося на будущее мне и иже с ними: нужно быть осторожнее при высказывании категорических субъективных и непроверенных суждений в трендовых постах… Вроде было очевидно — но попался. Спасибо сообществу за урок.
А как быть если мне нужно в возвращаемом значении иметь не реализацию класса, а его интерфейс?
И вообще это "замена вместо" или "дополнительная фича"?
Дополнительная. Какие сомнения в этом?
Слишком часто надо явно задавать тип переменной, чтобы его везде можно было заменить на var.
Это надо по сути другой язык делать.
У var есть польза, но я понимаю людей которые не могут ревьювить шарповый код с обилием varов. Банально разница в том, к какому подходу привык человек. Есть подход, основанный на концепции "важен код, т.е. действия, которые мы совершаем" и есть подход, основанный на концепции "важны типы, т.е. то, с чем мы работаем". Оба подходы имеют право на жизнь и более того, разные подходы по разному ложатся на разные задачи.
Но прикол в том что отсутствие varа и тех же лямбд (ранее) мешал следовать первому подходу. Тогда как в грамотных руках var и лямбды делают код более читабельным, а не наоборот.
Можно сравнить код с статьями/книгами. Слишком много воды — трудно уловить суть. Слишком мало воды — мозг либо отвык, либо просто не может слишком долго концентрировать на важных вещах. Оптимальный баланс найти трудно.
А можете рассказать как раскрывается информация о типах когда мы, например, записываем результат функции? Например, вот такой вот код:
.
var theStream = openStream();

.
Что именно за поток возвращает функция?
.
Ясно что есть контекст, но он может разрываться тем, что тебя отвлекли от кода или пришёл тикет на фикс какой-то другой срочной баги… Я уже не говорю о случаях, когда код был порефакторен кем-то другим (например, человек заменил значение, которое openStream() возвращает — а var остался).
.
Ясно также, что по-хорошему нужно точнее именовать метод. Но, на мой взгляд, подобные вещи будут приводить к тому, что имена переменных и функций начнут включать в себя ту самую "воду", которая до этого обозначала тип. Особенно когда речь идёт о больших проектах.
.
П.С.: Извиняюсь за точки — выше писал, какая-то фингя с проставлением энтеров между строками на хабре.
Что именно за поток возвращает функция?

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

NewSpecificWebStream theStream = createStream();
_IPCache = theStream.getIP();

.
Если мы меняем NewSpecificWebStream на var, то в случае рефакторинга (например, смены типа, возвращаемого из createStream() ) могут полезть ошибки — да, времени компиляции, но от этого всё равно не особо внятные. Таким образом, var не будет бить по голове только там, где возвращаются интерфейсные классы — да и то, очередной рефакторинг всё равно может привести к печальным последствиям.
Какие не особо внятные, какой рефакторинг, приведите конкретный пример
Ну, например, есть вот такой вот код:
var theStream = createStream();
_IPCache = theStream.getIP();

createStream() возвращал NewSpecificWebStream. А потом решил заменить возвращаемое значение на просто WebStream, у которого нету метода getIP() или этот метод называется по-другому. И рефакторинг при этом провели не мы, а кто-то другой в столюдной компании. При сборке в случае если бы вместо var был бы тип NewSpecificWebStream, ошибка возникла бы в строчке вызова createStream() — несовместимость типов. А с var ошибка возникнет в месте вызова метода, и придётся прыгать к декларации переменной, а потом ещё и смотреть тип, возвращаемый createStream().
Возможно, пример немного надуманный — если честно, у меня достаточно небольшой опыт работы с var — но когда я впервые услышал об этой фиче, мысли вроде такой заставили меня очень осторожно смотреть на var.
Вы поменяли тип возвращаемого значения, вам показали то место, где использовался тот факт что тип другой. Если бы там, например стояла декларация типа createStream явно, то возможно getIP мог бы не использоваться, но при этом все равно ругань была бы. Вам бы пришлось проанализировать все такие места — действительно ли он использует что-то из NewSpecificWebStream. Мне кажется, с учетом того, что надо делать маленькие методы, предпочтительней var
Я не понимаю, почему ошибки не полезут, если мы оставим тип явно. Я также не понимаю, почему ошибки для кейса var будут менее понятными, чем ошибки для кейса createStream().getIP() (т.е. когда мы объединяем цепочку вызовов).
Если тип будет прописан явно, то ошибки полезут тоже, естественно. Но когда мы глянем декларацию переменной, для вызова которой возникла ошибка — то мы увидим в коде не невнятный var, а конкретный тип, для которого выскочила ошибка.
Про вызов методов один за другим отписались выше, это справедливое замечание… Правда, чуть поразмыслив, я вспомнил, что в таких случаях — особенно если код незнакомый — приходится-таки прыгать по декларациям методов, чтобы смотреть возвращаемые функциями типы, что раздражает, и не хотелось бы получить подобный эффект ещё и для локальных переменных.
Если сравнивать именно читаемость, то такой подход хорош только в случае, если важно именно получение IP, а создание потока не имеет логической ценности для дальнейшего кода. Так, мы знаем только лишь, что здесь получаем IP из некого потока. Но если потом мы хотим использовать поток и далее, к примеру написать еще пару функций с его использованием, то нам нужно знать тип потока. Читая чужой код вы, не узнав тип, не сможете правильно его использовать, а, значит, придется либо разбираться в коде, либо посмотреть через подсказки IDE. Просто попробуйте модифицировать чужой код и сразу поймете чем он плох)
PS: в принципе, var вообще можно убрать и писать что-то вроде: IP = createStream().getIP();. Только вот это какой-то скриптовый язык получится.
Что именно за поток возвращает функция?

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

И что случится плохого, если другой человек поменял возвращаемый тип метода openStream?
Вы, кстати, не думали о таком концепте: иногда необходимо, чтобы тип переменной был жестко связанной с типом выражения? Например в c++ есть decltype.
Ясно также, что по-хорошему нужно точнее именовать метод. Но, на мой взгляд, подобные вещи будут приводить к тому, что имена переменных и функций начнут включать в себя ту самую «воду», которая до этого обозначала тип. Особенно когда речь идёт о больших проектах.

Т.е. по вашему лучше определение переменной в видеFileInputStream fos = ... нежели var inputStream = ...?
Справедливости ради.
А зачем вам это знать? Я правда не понимаю, объясните

Ага, я тоже так в первый момент подумал. Только вот это InputStream или OutputStream?
А если у вас две переменные (одна InputStream, другая OutputStream), вы как их различать будете? По имени или будете каждый раз бегать глазами к определению переменной?
Так я же не отрицаю что имя отвратное. Я лишь о том, что в данном конкретном говнокоде явный тип бы помог. Хотя, на самом деле, там все равно парой строчек ниже скорее всего будет read или write.
Ну так научитесь именовать чтоль переменные тоже правильно, а не только типы. Или вы аппелируете к тому, что разработчики стандартной либы более правильно именуют типы, чем разработчики вашего проекта переменные?
Как известно, с именованием всегда проблемы. На самом деле, я ни к чему не апеллирую. Более того, сам в опросе проголосовал за var + val. Т.к. считаю что должен быть простой способ делать final переменные (забавное словосочетание) чтобы провоцировать подход "final by default". Свой же первый коммент я написал исключительно
Справедливости ради.

Т.е. по вашему лучше определение переменной в видеFileInputStream fos =… нежели var inputStream = ...?

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

Теперь я гораздо более хорошо понимаю почему вы считаете, что var это плохо
Оу, да. Описался. Справедливо. Ну, считайте, там theLoadingStream и метод для загрузки чего-нибудь
Мое суждение очень локально. Я занимаюсь разработкой под Android уже более 5ти лет. Все мы знаем что нативный язык — это Java. Но в последнее время стал писать на Kotlin. Так там как раз такой синтаксис (val/var). Так что никакого отчуждения нет.
var — очень годная, полезная и нужная вещь. Java все-таки прогрессирует и медленными шажками идет в правильном направлении.
После года ежевечернего использования Scala объявление переменных с множеством дженериков в Java кажется сущим адом.
Программируя на Scala, почти никогда не использую явное объявление типов. Всегда понятно по имени переменной, какой у нее тип. И Idea конечно же подсказывает при автокомплите.
Прощай, проверка времени компиляции.
Здравствуй, ошибка времени выполнения, "внезапно" уронившая прод.
Если оно будет реализовано как в C#, то var можно использовать только в тех местах, где тип известен во время компиляции.
Прочитайте про то, чем отличается вывод типов в статической типизации от динамической типизации.
Ознакомьтесь с каким-нибудь языков, где выводов типов еще больше. (Haskell, F#)
Читал, знаком, и что? В Haskell статическая типизация. Он у вас даже не запустится, если тип нельзя было узнать во время парса.
Или вы хотите сказать что инференция типа во время компиляции — это динамическая типизация?
Перечитайте то, на что я отвечал и мой ответ. Что-то из этого вы не до конца поняли.
вывод типов в статической типизации от динамической типизации
Верно заметили. Вот вспомнил Haskell и сразу понял.
Пример приведите пожалуйста, что именно вы собираетесь ронять в рантайме?
На мой взгляд, единственный сильный контраргумент против var — это общепринятость использования интерфейсов в Java. Например:

List<String> names = new ArrayList<>();
Map<Long, String> map = new HashMap<>();

А дженерик-параметры уже в Java 8 не нужно дважды указывать, поэтому в приведенном примере минимум дублирующей информации.
С другой стороны, это же всего лишь локальная переменная — пусть будет классом, все честно. А в сигнатурах методов никто не мешает так и оставлять интерфейсы.
уже в Java 8
diamond operator еще в 7 появился.
Да, там выше написали про вывод типов.
По факту контраргумент — вопрос привычки. За пределы метода ArrayList всё равно не вылезет, а внутри метода вам большой разницы нет, особенно когда вы этого типа перед глазами не видите. Наоборот, если вы формируете список в методе и возвращаете его наружу, вам может захотеться в конце вызвать какой-нибудь trimToSize() для экономии памяти, поэтому более специфичный тип внутри метода может пригодиться.
Как всегда в подобных обсуждениях var/auto находятся люди только что вылезшие из бункера и не ознакомившиеся с описанием фичи, считающие что их любимый ЯП собираются испортить динамической типизацией из PHP, JS и т.п. :)

Этих людей стоит успокоить: динамическая типизация в джаве давно есть, только синтаксис адский :) Если на JS было бы
var a = "abc";
var b = a.replace("a", "b");

То на Java будет
Object a = "abc";
Object b = a.getClass().getMethod("replace", String.class, String.class).invoke(a, "a", "b");

Динамическая типизация в чистом виде!
Где в данном примере динамическая типизация? Здесь её как раз нет совершенно.
Ну-ка, объясните, в чём разница между динамической типизацией и reflection?
Хм, в определениях? Я может не понимаю вопроса, но не могу придумать контекста, где это было бы одним и тем же или хотя бы чем-то похожим.
В том, что код:
var item = new { Age = 18, Name = «Ivan», LastName= «Ivanov» };
Console.WriteLine(item.Age);
Console.WriteLine(item.Name);
Console.WriteLine(item.LastName);

Будет преобразован компилятором в:
AnonymousClass_666 item = new AnonymousClass_666() { Age = 18, Name = «Ivan», LastName= «Ivanov» };
Console.WriteLine(item.Age);
Console.WriteLine(item.Name);
Console.WriteLine(item.LastName);

А теперь сравните его с рефлекшеном.
Это детали реализации, которые никого не волнуют в заданном контексте. В рефлекшне JVM тоже может сгенерировать нативные методы, если конкретный метод часто вызывается.
Вы в этом точно уверены? Да и руководство прямо говорит об обратном:
Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
docs.oracle.com/javase/tutorial/reflect/index.html

Если бы проблемы с Reflection не было, то и не было бы такой библиотеки, как ReflectASM.
Просто смешно от консерватизма явистов. Никто не заставляет писать var везде — пишите там, где явно понятен тип из выражения справа, типа
SomeClass.SomInternalClass<String, Integer> foo = new SomeClass.SomInternalClass<~>();
var снижает читабельность? да у меня глаза кроваточат от строки выше.
А вообще зачем этот динозавр когда есть котлин.
static import com.some.SomeClass.SomInternalClass;
Котлин сыроват и после java выглядит набором свистелок. Вот тут о его проблемах написано подробнее.
Даже это по факту мелочи. А вот когда используешь функциональный стиль на всю катушку, возникают типы шире экрана (например, BiFunction<BiPredicate<String, Integer>, String, BiPredicate<String, Integer>>). При этом он нужен реально в пределах ограниченного скоупа.
По факту автоматический вывод типов уже работает в восьмёрке для аргументов лямбд. Кто использует функциональное программирование на всю катушку, у того больше половины переменных — по факту параметры лямбд, и у подавляющего большинства тип выводится автоматом. По факту этот JEP — логичное распространение существующего механизма, а не что-то новое.
Меня больше парит, что предложенные var и val визуально похожи. Я при заполнении анкеты предложил оставить var, а вместо val использовать const (благо это уже ключевое слово), но ко мне вряд ли прислушаются.
Интересно
Есть код скажем такой
var somevar = somevar2.getSome();
И есть конструкция
Some somevar = somevar2.getSome();

Как в первом случае узнать какой реально тип я получаю для дальнейшей работы?
И как в первом случае Ide найдет мне в контекстной подсказке список функций которые возвращают именно тот тип что объявленная мной переменная?
найти где объявлено somevar2 получить ее тип. Найти у типа getSome, получить тип результата он и будет типом somevar
Ну то есть лишние телодвижения при работе с чужим кодом (или со своим который писал достаточно давно что бы уже забыть детали)
Если вы разработчик IDE, то да, если пользователь, то IDE это сделает для вас
Что ide сделает за меня?
Я смотрю на код с var и пытаюсь понять что я получил в итоге вызвав эту функцию и не вижу этого.
посмотрите, как выглядит работа с ide kotlin, например,
Как только вы вводите переменную сразу же подсказка с типом, еще обычно можно наводить просто мышкой и тебе расскажут все про идентификатор под курсором.
По типу результата метода getSome(), очевидно. В чем проблема?
Разница только в том, что если вы напишете

AnotherType somevar = somevar2.getSome();

Вы поймаете ошибку компиляции, что тип Some не может быть приведен к типу AnotherType. Как раз потому, что компилятор сравнит результат метода getSome() и объявленный тип переменной.
Больше никакой разницы нет.
И как в первом случае Ide найдет мне в контекстной подсказке список функций которые возвращают именно тот тип что объявленная мной переменная?

При парсинге кода IDE посмотрит, что возвращает somevar2.getSome() и var somevar будет именно этого типа.
Это и контекстных подсказок тоже касается. Тип переменной x, объявленной в виде var x = getSome() выведется из типа возвращаемого значения getSome().
Еще раз

Я пишу int x = obj.*******
Вместо звездочек мне ide покажет список функций которые возвращают int

Если я вместо int пишу var то ide начнет мне отображать уже список всех доступных функций которых будет значительно больше
Я работаю под линуксом…
Можете словами объяснить какой там алгоритм?
Считывание нейроимпульсов, не иначе. Я не вижу другого способа угадать, какой же метод/переменная потребуется в var. По той ссылке также ничего полезного не увидел (да и не смог бы).
Я просто недостаточно внимательно прочитал описание проблемы, извините. См. ниже обсуждение, как это можно сделать сконвертировав в var после набора и непонятнку как отличить ситуацию когда надо int x = y.IntMember и int x = y.StringMember.Length.
В таком случае согласен, отфильтровать методы по типу не получится.
Хотя лично я предпочитаю написать obj.getSomeValue(), а потом сделать Introduce local variable, получив final SomeType someValue = obj.getSomeValue();
Извините не понял. То есть вы совершенно точно знаете тип, но не знаете ни одной части имени члена?
В таком случае да, набираете int x = y. выбираете член, потом можно автоматически переконвертировать int на var.
Еще вопрос. Как IDE узнает, что когда вы набираете int x = y. вы хотите написать целый член x а не например x.ToString().Length?
1) Я знаю что мне нужно получить и исходя из этого уже выбираю нужную мне функцию.

2) ну тут сложнее для ide и она уже видя что я набираю значение которое не подходит под ее шаблон начинает использовать мой шаблон
Ну так укажите тип переменной и пользуйтесь этой фичей. В чем проблема то?
Код чужой, но это же не запрещает вам указывать типы (если конечно у вас не драконовские стайлгайды, но это уже другой вопрос).
Это понятно
Вопрос в другом
Я пытаюсь понять насколько удобной будет новая фича что бы ее можно было использовать
А как оно узнает, хочу ли я сделать:
int x = object.IntMember()
или
int x = object.StringMember().IntMember()
Выводит ли оно StringMember()?
var прекрасен когда дело доходит до рефакторинга. Когда у вас есть методо который раньше возвращал конкретный класс, а потом вы решили, что он должен возвращать абстрактный класс или же вовсе интерфейс.
с var проблем не будет, если сигнатуры методов остались теже.
Ну хоть не как в ПХП
if (борщ > 12)
{
echo "а борща то нет, без декларирования живем";
}
Судя по результатам опроса (ссылка в статье), с большим отрывом победил вариант «var and val» как в Scala, а не просто «var», как в С#. «auto» занял предпоследнее место.
Извините, не удержался
а не просто «var», как в С#
Мы не станем рабами (с)
То, что старушка Java активно взялась перенимать фичи из современных языков программирования, не может не радовать. Как ни крути, на Java пишет огромное количество людей, и через такие вещи как лямбды, REPL, автовывод типов, все эти люди приобщаются к современным подходам к разработке. Надеюсь, что разработчики языка найдут способ внедрить еще хотя бы case classes и pattern matching. Конечно, это не сделает из Java конфетку, но хотя бы базовые идиомы и обычный код на Scala не будут выгляеть для Java-разработчиков полной дикостью.
Странный спор. Во всех современных языках программирования есть var/val/let, который применяется практически везде. А вы спорите, полезен он или нет. Этот спор уже давно и однозначно разрешён.
var и let это разные вещи
var x =… говорит — это переменная x, тип которой выведен из выраженния справа
let x =… говорит — это выражение значение которого можно получить по имени х
Просто var научит вас использовать говорящие имена переменных, которые подразумевают их тип, что сделает код еще более чистым и читаемым...
UFO landed and left these words here
Да ладно, не такое и серьезное изменение, если вдуматься. Ну теперь в плохом Java-коде разобраться станет чуть сложнее, а в хорошем… проще. Но, конечно, чуточку жаль, ведь теперь вместо канонического:
for (Map.Entry<MyTrickyWrapper<String>, MyDomainObject<WithGenericType<AndSubtype>>> e : m.entrySet()) { ... }

Можно будет написать
for (var e : m.entrySet()) { ... }

Бедные пользователи notepad, ну как же им будет сложно понять такой код...
Напомню, что уже сегодня можно писать
m.forEach((key, value) -> {...});

Есть некоторые ограничения, но всё-таки. Заметьте, что здесь уже выводятся автоматически типы key и value и никто не жужжит, все пользуются.
Тише, тише!
А то сейчас прознают про это и поднимут на change.org петицию "Уберите в Java автовывод типов для аргументов лямбд"!
А заодно и лямбды тоже уберите, ага. А то знаю лично некоторых консерваторов, говорящих о том, что лямбды не нужны. Это какая-то клиническая форма консерватизма уже.
Да боже мой, даже ежу понятно, что var user = new User() в 100 раз удобнее и читаемее чем User user = new User().
Господа консерваторы, Вы бы посмотрели на текущие реалии — во всех новых языках сейчас так.
Java развивается, меняется и это хорошо, радоваться надо, а не ныть.
Наличие "новой" функции в языке не делает её автоматически хорошей. Плохой собственно тоже. А удобство — личное дело каждого, зачем навязывать своё удобство другим людям?
Не видел еще ни одного человека, который бы попробовал синтаксис Scala, Kotlin, Swift, Go, Nim etc. и сказал бы «не ребят, вообще не удобно». Не зря же сейчас многие новые языки именно так дизайнятся.
Есть разница в дизайне языка где инференция типов вот таким образом предусмотрена изначально (Haskell), и там где это делают после факта в качестве примочки, что (вероятно) влечёт за собой кучу проблем с читаемостью и пониманием кода.
Вопрос не в нытье
Вопрос в том как лучше адаптироваться в новой реальности ))
Ну сейчас стадия где-то между отрицанием и торгом, до принятия ещё пару шагов.
Автор прав тем что java чисто консерваторский язык, и то что многим другим программистом кажется очевидно и просто для джависта вызовет когнитивный диссонанс.
Вообще-то, var в C# был добавлен не ради краткости, а прежде всего для поддержки анонимных типов, на которых (в числе прочего) базируется LINQ.
Все таки LINQ базируется на перечислителях, а анонимные типы немного из другой истории, хотя и используются преимущественно с LINQ. И VAR в данном случае не более чем средство для удобной работы с ними, т.к. все анонимные типы не более чем техническая прослойка с временными переменными, тип которых не несет полезной информации.
Хотя, порой хочется бить шлангом за использование анонимных типов где не надо
Не для "удобной работы", а для какой бы то ни было работы с анонимными типами необходим var!
Исключительно из-за строгой типизации языка и особенностей работы VAR. Но слава богу, что не ввели тогда dynamic!
PS. Согласитесь, что VAR и анонимные типы это 2 разных фичи, хоть и связанных в использовании между собой. И VAR может эффективно использоваться и без анонимных типов, а вот анонимные типы без VAR уже практически невозможно. А в целом это спор о курице и яйце получился))
Сходил по ссылке в опрос разработчиков. Ладно еще var. Но большинство за val+var. А на третьем месте предлагают var и let. Это же ужас. Например, открываете программу, а там
10| let a = 7;
20| let b = 5;
Вот сейчас было особенно тепло и лампово, но вырвиглазно. И слегка бейсиковато. И даже если номера строк отключить. Это же теплый ламповый ужас, какое счастье что подобное они не сотворят, а var просить им можно. Хотя, если сделают var, то скорей всего сделают и val, и если они это сделают, то это будет значить, что за этим стояли скалисты.
Но вообще, тогда лучше уж и лаконичней так:
User u = new ("вася")
Хотя new со скобками тоже тут не очень нужно, но без него уже другие приколы будут, так что это был бы оптимум. А вот с NetUtils.getOutputStream(sock) хуже — не всегда понятен тип возвращаемый, с другой стороны иногда тип понятен, и когда он понятен, то действительно, писать его не хочется.
Я на Бейсике использовал let (точнее LET), когда ни Clojure, ни Java не было вообще.
На старых бейсиках оно было.
Потом даже в бейсиках более новых от него отказались. С тех пор, как видишь let, это ассоциируется с древним бейсиком. Конечно новички это так не воспринимают, и для них это ничего не значит. Я подозреваю, что заминусовали меня новички.
Зачем в clojure решили использовать именно let, загадка. Думаю, от этого он потерял некоторое количество почитателей.
В лиспах с первых версий тоже есть конструкция с именем LET. Так что не факт, что не факт, что её ввели в BASIC.
Классный опросничек в начале статьи приведён. За вариант "может сделем var как в C#" — 80% народу за или не против, а по поводу варианта "может сделаем auto как в С++" 70% людей категорически против. А чем же, скажите мне, принципиально отличается var в шарпе от auto в плюсах?
А кто голосовал против C++ наверное и сами не знают как оно в C++ работает.
Может просто потому, что var более естественно выглядит, чем auto, не?
auto — это какой-то уж слишком общий термин (Помню, как сам сильно удивился выбору такого ключевого слова в плюсах, я понимаю логику такого названия, как программист, но с точки зрения простого обывателя такое впечатление, что все делается для того, чтобы код мог читать только специалист. Зачем бесконечно изобретать велосипеды даже в таких простых вопросах, когда уже все давно придумано, принято и много лет успешно используется? Специально, чтобы не как у других? Чтобы выделиться? Ну, это глупость! Это только снизит переносимость и повысит порог вхождения!), а переменная (var) — она и в Африке переменная, поймет даже ребенок, вполне говорящее и читаемое ключевое слово, используемое явно и неявно (var1, var2,… Да, быдлокод, но через это проходили все, в процессе обучения.) начиная от истоков IT, с которым знаком каждый школьник. И короче на символ! :D
В плюсах это обусловлено было обратной совместимостью — auto всегда было зарезервированным ключевым словом, а введение var поломало бы старые программы, где были переменные с именем var.
Как я и написал выше, я понимаю логику такого выбора, но мне кажется, что можно было бы обойтись меньшей жертвой в угоду читаемости, при необходимости пофиксив на месте старые проги, коих, я думаю, было бы не так много (тем более, что это явный говнокод), приняв var, чем теперь иметь auto навеки… Для старых прог это всего лишь исправление имени переменной, а не тотальная смена семантики, it's not a big deal… И не думаю, что такого кода на жабке сильно меньше, тем не менее это не помешало принять правильное решение… Более того, если старые проги до сих пор компилируются современными компиляторами, а не просто крутятся где-то на забытых пентагоновских серверах десятки лет, то считай, что они развиваются, поэтому не будет проблемой провести мелкий рефакторинг перед следующей компиляцией...
var — простой сахар, не хотите — не используйте. Не стоит придумывать себе проблему там, где её нет.
проходили уже все это в C#, тоже было много гнева и воплей как появился var, но потом все привыкли, оказалось удобно. мое субъективное мнение, в том, что вывод типов рулит и чем меньше мне их придется писать явно руками, тем лучше.
Когда начал осваивать Java (после использования C#) очень удивило отсутствие var.
Даже в С++ уже добавили auto.
Отсюда и главная претензия к var — риск снижения читабельности
Это Вы разработчикам на python'e и т.п. расскажите как отсутствие типа снижает читабельность.
UFO landed and left these words here
Тем, что это имя класса. А var — обозначение любого типа. Object x = 4 сейчас создаёт объект Integer, а мне не нужен объект.
Object x = 4 нельзя написать. Я уверен, что Ваш любимый "var" просто станет обёрткой "Object" в красивом виде и всё. Компилятор сам тип приведёт и всё.
var будет удобен в Java лишь в объявлении переменной с длинным названием типа.
Нет. На самом деле с любой длиной в названии типа.
Вы делаете var x = someFunction();
И уже больше никогда не паритесь, если вам нужно будет на этапе проектирования поменять тип, возвращаемый someFunction(); (не надо будет по всему коду менять типы переменных).
И словите большой привет, когда разные перегрузки станут по ошибке возвращать разные типы. И хорошо, если эти типы будут несовместимы, об этом сругнётся компилятор, а если это разные потомки одного базового класса, то баги можно искать неделями и совершенно в других местах.
overloaded methods, возвращающие РАЗНЫЕ типы? В Яве (и в C++) такое невозможно.
Можно сдуру. А можно по невнимательности. А ещё можно специально. Кейсы бывают разные, и, например, такие перегрузки очень лаконично и правильно входят в идеому математических библиотек, где оператор может давать результат, мягко говоря, отличный от операндов тип.
ну и чем мешает var?
хочешь явно тип переменной — указывай по-старому
если у тебя обобщённый алгоритм — пиши var и не парься
«По моим ощущениям, хороший код не пострадает. А вот плохой код может стать еще хуже. Ну и бог с ним.»
Ню — ню)…
К сожалению далеко не все пишут ХОРОШИЙ код, а вот насчёт «Ну и бог с ним.» — это наврядли получится… с этим ПЛОХИМ кодом, тоже рано или поздно придётся кому — то работать, фиксить его, рефакторить, дописывать, и он уж точно тогда эти VAR не похвалит))
Не вносить в язык синтаксический сахар из-за страха, что им неверно воспользуются и нагородят нечитабельный код, вероятно, исходит от тех людей, которым нравится переписывать одинаковые разной степени монструозные конструкции из раза в раз.
Мда, прочитав комментарии становится понятно почему java так медленно развивается. Добавили отличную фичу, причем ей не заставляют пользоваться в обязательном порядке. Но все равно есть недовольные
А почему вместо val не использовать final, либо зарезервированный const? А так за.
Вариант const предлагали, и я за него голосовал. Но почему-то большинство против. Демократия, чтоб её. У final для локальных переменных уже есть семантика, тут пришлось бы навешивать дополнительную. Не уверен, что это хорошо.
первое не скомпилируется.
А вот если будет
var x = "y"; (то же самое что и String x = "y")
Object z = "y";
То x.Length скомпилируется, а z.Length не скомпилируется
Первое нельзя написать.
Но можно var smt = someInstance.someMethod().someOtherMethod();
при этом smt автоматически получит конкретный тип, являющийся типом всего выражения. Не Object.
В дополнение к сказанному: Object не является всеобъемлющим типом. Он не супертип для примитивов.
Вот после этого все и кричат, что Java тормозит. А по факту тормозят те, кто глаза закрывает.
var – не просто сокращение записи, не просто повышение читаемости кода.
Это новый уровень обобщения. Позволяет не фокусироваться на конкретном типе переменной, а сосредоточится на алгоритме.
var a = streamFactory.openForWrite();
a.write(1);
var b = a.bufferedCopy();
b.write(2);
Код не привязан к конкретным типам.
Я могу поменять первую строку, остальное останется без изменений (если алгоритм совместим с выведенными типами).
При всей лаконичности динамических языков у нас остаются все прелести строгой статической типизации.
Так и до плюсовых шаблонов недалеко, с чем вас и поздравляю, серьёзно. Может когда-нибудь.
Ну не нааадо! Если я захочу всяких финтов и сокращений, я чонить новое, модное и хипстерское возьму. Оставьте мне мою тихую гавань в покое!
А заодно и лямбду и еще половину языка обрежем. Мыж максималисты, если резать, то резать все и без разбору!
Я знаю что у многих языков есть Var, чем он так хорош для Java я честно не понял.
В Rust он для сокращения текста, что соответствует их политике, в C# (как говорит сударь чуть ниже) для анонимных типов.
А для чего тут? Чтобы перезаписывать ее разными данными?
Нууу не знаю, у меня с фантазией на имена переменных никогда проблем не было.
А вот когда читаю чужой код с чемнубдь типа этого:
SomeAnswer sa = obj.someFunc(); — я сразу вижу какие данные он возвращает. (Собственно чем мне Java и нравится. Длинно но четко и ясно)
var sa = obj.someFunc(); — тут же надо будет делать дополнительные движения, чтоб узнать что она делает.
Вобщем ИМХО: для меня минус этого нововведения больше чем плюс.
PS милости просим минусовать, заплючовать вы меня все равно не сможете.: р
В Rust он для сокращения текста, что соответствует их политике, в C# (как говорит сударь чуть ниже) для анонимных типов.

В rust вообще let и у него сильно другая семантика, близкая ко всяким ML'ям. Это биндинг. В частности, тип биндинга может меняться в новом скоупе без изменения его имени. Т. е.
let param = "-123";
let param = param.parse::<i32>().unwrap();
println!("{}", param + 3); // -120
В Rust он для сокращения текста, что соответствует их политике, в C# (как говорит сударь чуть ниже) для анонимных типов.
А для чего тут? Чтобы перезаписывать ее разными данными?
Эту переменную нельзя будет перезаписать «как угодно». Типизация остается все также статической.
SomeClass a = new SomeClass();
a = new SomeClass(); // скомпилируется
a = new OtherClass(); // не скомпилируется
var a = new SomeClass();
a = new SomeClass(); // скомпилируется
a = new OtherClass(); // не скомпилируется
var sa = obj.someFunc(); — тут же надо будет делать дополнительные движения, чтоб узнать что она делает.
Нужно будет просто навести курсор на var и ide скажет какого типа эта переменная.
Читаю весь этот холивар и удивляюсь… Я не знаю Java, но знаком с C# с бета-версии первого .NET Framework и довольно часто пишу что-то «для себя» (для автоматизации рутины). Ключевое слово var появилось в C# не для того, чтобы программистам было необходимо меньше печатать — для этого Microsoft развивает IntelliSense в Visual Studio. И не для того, чтобы код выглядел красиво — для этого есть гайды.

Ключевое слово var было добавлено в C# одновременно с анонимными типами и в первую очередь для их поддержки. Какой тип вы укажите у переменной в следующей конструкции:
var point = new { X = 1, Y = 2, Z = 3, T = 4};

А анонимные типы появились для того, чтобы можно было их использовать в LINQ-запросах и лямбда-выражениях, поскольку описывать отдельный класс на каждый чих, который нужен только в одной-двух строчках программы, да и то в качестве промежуточных результатов — это захламление проекта. Пример реального кода:
var list = json["data"].Select(row => new { Address = row["i"].Value<String>(), Port = row["p"].Value<String>() });
foreach (var item in list) {...}

PS Поздно увидел комментарий lasalas, который, в общем-то, говорил о том же самом. Уступаю пальму первенства.
Возрадуйтесь: jigsaw точно будет в девятке, а var не факт. Насчёт aot ещё неизвестно, благо ли это.
Тагир, тут вопрос не в каком релизе будет, а когда будет этот самый релиз. Да и у Oracle хватает интересных задач, не хотелось бы чтобы они тратили ресурсы на сахарный var.

Как я понимаю, фича оказалась неожиданно несложной, поэтому решили её поковырять. Type inference уже был сделан нормально в восьмёрке. А когда будет релиз — известно, 23 марта 2017, меньше года осталось.
А я вот не понимаю, в чём проблема. Даже если var введут, то ни кого же не заставляют им пользоваться. Вон в C# сколько уже var присутствует, но во многих проектах его вообще не используют, а указывают тип явно.
В C# var придумали не для неявного указания типа. Он там нужен для анонимных типов.
Ясно. Я не шарпист. Значит, философия использования var в шарпе не та, поэтому напрямую с шарпом сравнивать нельзя. Наверное, мой вывод стоило бы записать как "Это значит — реально var в шарпе не нужен". Но делать выводы вроде "раз он в шарпе не нужен — значит и в java тоже не нужен" — некорректно.
Интересно, а как много проектов сейчас используют var как имя переменной или класса?
Много. Но авторы JEP учли это. Переменные var/val никто не запрещает (сломаются только типы, если у вас объявлен class var). А так вы сможете писать без проблем:
var var = 0;
val val = var;
И это не сломает читабельность кода, нет-нет. Извините, но если код var var = Var.var(); будет валидным, это ж просто варварство будет. /хотя он и сейчас валиден, лол/

Не, с одной стороны это меньшее из зол, согласен. С другой, это всё равно дерьмовое решение. В С++ использовали auto как раз потому, что коллизий с существующим кодом практически не было, в отличии от var или let. Также не самое приятное решение, хотя мне чисто по смыслу перевода нравится куда больше всех этих var, val и let. Написали «тип — автоматически выведеный» и не соврали. А с «пусть» или «переменная» уже непонятки. Но да кого моё мнение волнует?
Ну писать новый код в таком стиле явно не стоит. Это сделано, чтобы старый не сломался.
Если они уберут объявление типов и вообще его вырежут, никто не мешает остаться на версии, где оно еще присуствует.
Для меня var — это взрыв мозга.
Вы не заметили до сих пор, что большинство кода, написанного в эпоху Java 1.0, до сих пор компилируется, а скомпилированный, как в те годы, так и сейчас, успешно выполняется? Джава — не тот язык, из которого могут просто взять и убрать что бы то ни было. За это её и любим.
Вообще, это посто ввод var. В таком случае никто не мешает использовать стиль по старинке. Паника off.
Из этого JEP мне не столько интересен var, сколько val. Потому как писать "final T v = new T();" мне совсем не нравится, слово final замусоривает код, при этом подчеркнуть что переменная финальная — полезно. Как говорится "Make val, not var"
Ребят, кто любит использовать финальные переменные в локальном скоупе, можете мне наконец объяснить — зачем? Ну ведь реально — просто замусоривание кода.
Неизменность переменных в локальном скоупе? Зачем? Нет, если вы пишите методы по 100-200 строк — тогда да… но разумный-то размер метода вписывается в 10-30 строк, и там пользы от этого нет!
В основном (придётся немного покапитанить) это подсказка IDE и компилятору и ограждение себя от случайного затирания значения переменной значением другого выражения. Про предварительное облегчение передачи значений в методы анонимных классов говорить не буду ибо компилятор и так заставит.
Так же радует, что у вас основной аргумент против не именно необходимость переиспользования переменной, а всего лишь "замусоривание кода".
Ну а когда всё же реально потребуется изменяемая переменная, она будет единственной изменяемой, и её изменяемость и необходимость её изменять будет явно заметна.
Неизменяемость переменной, на мой взгляд — того же типа хинт тем, кто читает программу (особенно с помощью IDE), как и статическая типизация, хотя, конечно, более слабый.
Да, и кстати — я сам никогда не набираю слово "final" руками, для того, чтоб его вставить, всегда использую только подсказки и опции IDE, так что оно не добавляет мне работы.
Про предварительное облегчение передачи значений в методы анонимных классов говорить не буду ибо компилятор и так заставит.

А в лямбды не заставит, т. к. там достаточно effectively final.
UFO landed and left these words here
Кстати
Гораздо интереснее а можно ли будет объявлять метод с возвращаемый типом var?

В C# без var нельзя обойтись в анонимных типах.
collection.Where(x=>x.IsFlag).Select( new { x.F1, x.F2 });
потом в методе уже можно оперировать анонимным типом в скоупе метода.
В остальном не более синт. сахара, беда в том, что программисты понатыкают эти вары где надо и где не надо.
Вывод типов уже есть в джаве для лямбд. Логичный шаг — сделать для локальных переменных.
Когда хорошо: когда тип переменной полностью ясен из правого выражения (new, Factory.create, присвоение поля, etc...). Когда плохо: когда тип не ясен без ползания в сторонние api (var out = manager.getOutput()), когда тип нужно привести к интерфейсу (Map<String,String> cache = new MyPersonalLocalCacheImplementation()).
Ухудшится ли читаемость кода? Бесспорно. Однако, когда были введены лямбды, в которых встроен вывод типов, никто сильно не протестовал. Так что дело спасут умеренное использование и более выразительные названия переменных.

P.S. опять разработчики джавы пытаются сэкономить буквы, но делают это не там. Уже давно пора ввести properties в джава и убрать весь этот уродский мусор с геттерами-сеттерами.
Насчёт геттеров-сеттеров — подозреваю, что всё тут сильно завязано на рефлексию и её подчёркнуто ограниченное использование. Нельзя в Java делать properties просто синтаксическим сахаром.
Как раз можно. Другие языки как Groovy, Scala, Kotlin генерируют без проблем Java-совместимые проперти. Единственное, что может дать проблемы — это JavaDoc, которому нужен исходник с геттерами-сеттерами.
Воспользуйтесь уже ломбоком и будет вам счастье с геттерами-сеттерами. Вот только иногда всё-равно приходится переопределять геттер/сеттер, если поле в итоге не просто проперти.
Ну в Java уже есть такая опция, которой принято не пользоваться, как объявление нескольких переменных одним оператором. Будет ещё одна...
Какой смысл писать
List<int> a = new List<int>():

Когда можно написать
var a = new List<int>();

Другой случай, когда пишется
var a = function();

Это неудобно, нужно заглядывать внутрь определения функции function, чтобы знать, что она возвращает.
Таким образом пишите var тогда, когда и так понятно, какого типа должна быть переменная, никуда не ходя, и будет счастье.
После плюсов это была главная вещь, которая резанула глаза (и продолжает резать) в c#\Java. Все более-менее сложные объекты приходится создавать через new, но, при этом, на коде это никак не сказывается. То есть нельзя по какому-либо участку кода сказать, нужно ли переменную проверять на null или нет. В плюсах в этом плане куда более удобный для понимания синтаксис. Как минимум, понимаешь, в каком случае переменную нужно проверять на null и уточнять её тип, освобождать память и тп, а в каком — нет. И сейчас в меня какашкой бросят за такие слова.
Какашкой не бросим, но без примеров — пустословие какое-то получается.
Банальщина.
@Nullable
List a = null;
List b = new List():
int c = 0;
/*...*/
if (a != null)
{ a.append©; }
b.append©;

И ни единого способа узнать посреди кода о свойствах объектов без помощи IDE либо пролистывания кода. У плюсов всё подругому.

std::list* a = new std::list();
std::list b;
int c = 0;
if (a != nullptr)
{ a->append©; }
b.append©;

В плюсах b сравнивать просто не имеет смысла. А для a сразу видно, что нужно следить за памятью, как минимум, помнить, кто за неё в ответе. /* Надеюсь, обойдётся без мусорных холиваров. */

И, да, я не гарантирую правильность Java-кода. Чукча не писатель.
Вы даже не представляете, какой осадок у меня выпал, когда я посмотрел на отхабренный комментарий… Это просто ©ча©тье какое-то!
Я, аналогично, не писатель c++ — можете пояснить фразу «В плюсах b сравнивать просто не имеет смысла»?
С моей точки зрения (как это в c++ я не знаю) — b объявлено, но не инициализировано (в этом случае для локальных переменных в java сломается компиляция). Помимо этого я вижу, что b вроде как объект, а не ссылка на объект (но вот тут сознание буксует, чем это нам аукается — с не менеджед языками я не работал уже бог весть сколько).
b объявлено, но не инициализировано

Нет, b тут будет как раз инициализировано.

Как я понял, iCpu имеет в виду, что b не может быть null'ом вообще, а 'a' — может (потому что это указатель).
Ага, спасибо… Привык уже, что в java всё, кроме нативных типов, является ссылкой…
Я не совсем в курсе, kotlin — это новое название Java или просто Another one bites to JVM? Я понимаю, что компилятор должен быть умным, но… Он был, есть и будет тупым. https://habrahabr.ru/post/164027/
1) Мы обсуждаем дизайн языков, в частности у вас проскочило сравнение C++, C# и Java — я высказал мнение как это должно быть
2) Для Java программистов имеет смысл посмотреть н Kotlin так как там не только внесли новые фишки, но и смотрят на interoperability c Джавой
Кстати, в C# 7 тоже планировали non-nullable types но вынесли похоже из последней редакции.
1) Вводятся квалификатор типа "?" и оператор "?.". Казалось бы, причём тут "*" и "->"? К тому же интересно, как компилятору проверить то, что известно только в реалтайме?
2) Я сейчас выскажу достаточно противоречивую точку зрения, но… Чтобы нормально «посмотреть» ЯП, нужно не один день затратить. Иногда хорошая, казалось бы, идея на деле оказывается не самой удобной. К примеру с (1), в c++ можно сделать шаблоны, которые будут внедрять все эти фичи задёшего. Но что-то никто не торопится это делать. Необходимости нет.
Так вот, можно бегать и смотреть, какой из ЯП наиболее сладок для тебя. А можно не бегать, а выбрать один и изменять наиболее неприятные его места. Теорема Эскобара применима.
1) Вы почитайте — он не проверяет, то, что известно в рантайме, он требует от вас кода проверки, если ссылка nullable а вы ее используете не проверяя.
2) Давайте сделайте шаблон, чтобы
x -> SomeMethod() требовало бы проверки а
if (x!=NULL)
{
x-> SomeMethod()
}
компилировалось бы
3) Еще можно поверх Джавы проверять статическим анализом (что и делают IDE, но вам же нужно без IDE)
1) И не даёт нормально приводить типы между nullable и non-nullable. Где же здесь подвох?
2) Во-первых, «можно сделать» != «ща, за 3 минуты в комментах забацаю». Во-вторых, «внедрять все эти фичи» != «внедрять фичи с полным сохранением синтаксиса». Если мы это учитываем, то почему нет? Никто не запрещал ни перегружать оператор ->, ни добавлять функторы, ни писать макросы. Самое тупое и быстрое, что я могу придумать, это
#define call(a,b) if (a) a->b;
а в бустах давным давно лежит boost::optional. Да, написать шаблон, который оборачивает возвращаемые типы всех методов, не так просто, но возможно.
3) Как и плюсы точить vargrind'ом или PVS-studio.
1) Что такое "нормально"?
2) В котлине есть способ так же аннотировать окружающий Java код. Посмотрим, что из жтого получится.
3) Дада, только в Java есть уже стандартый nonnullable атрибут, насколько я знаю, а в ,NET часть FW уже аннотирована.
Есть разница между теоретической возможностью сделать что-то похожее, полноценным языком и поддержкой экосистемы.
1) operator=
2) Я, видимо, не понимаю, чего вы здесь от меня хотите или, наоборот, чего пытаетесь впихнуть.
3) MyClass class; //Nonnullable since long long ago in the days when ALGOL was still in some use
1) Non nullable так можно привести к nullable, а наоборот только со значком "я уверен в себе и разрешаю здесь случиться эксепшену"
2) Я в том смысле, что если вы и изобретете свои типы на C++ то надо еще будет обучить этому самому окружающие библиотеки — в котлине этот вопрос решен.
3) Я не очень понял, что вы хотите этим сказать. Если что можно написать коммент, то надо еще поддержать это в инструментах. Если это означает value тип в C++, тогда проблема переезжает в ссылки.
1) То есть, указатели с принудительной проверкой. Можно взять адрес, обратное — неверно.
2) Если под «этот вопрос решен» вы имеете в виду «с тех пор, как это вошло в стандарт, этим все пользуются», не вижу существенных отличий. Если же смысл в «библиотеки не придётся переделывать под новый синтаксис», то… Да ладно!
3) Единственный смысл ссылок — передавать в функцию объект, а не значение. Все побочные использования — синтаксический сахар, окромя move-семантики.
Я имею в виду простую вещь — любые попытки доказать плюсовику «а у нас можно создавать объекты, которые не обращаются в null» вызывают тупую реакцию «вы что, 20 лет шли к тому, чтобы создавать объекты на стеке?» Весь этот синтаксический сахар с короткими записями условий и автоматический возврат null при любом неверном чихе не меняет простой вещи: ваш язык упёрся в указатели. Притом. создатели ввели новый синтаксис, чтобы показать — это не указатели, но это чёртовы указатели. Они ведут себя, как указатели. Они пахнут как указатели. Они на вкус как указатели. Даже выглядят как чёртовы умные указатели, ведь в JVM нет способа заглушить сборщик мусора. Так почему мне пытаются втындюрить, что это не указатели, а манна небесная, и что все IDE их будут поддерживать, в отличие от плюсовых, в которых… всё отлично поддерживается? Или вся проблема в том, что компилятор плюсов при стандартных настройках — не истеричка?
1) Ненене, все указатели, можно сделать два указателя на один объект и они будут не nullable оба.
2) Не проверял, но есть возможность добавлять внешние аннотации.
3) Нет это не указатели, это именно ссылки — нет никакой арифметики. И non-nullable ссылки это ссылки то же. Две non-nullable ссылки могут указывать на один и тот же объект
1) 3) А вы в курсе, что уже 21 век и что unique_ptr, shared_ptr и weak_ptr — это часть стандарта уже более 5 лет?
2) Это, конечно, круто, но это просто ужасно. Вы понимаете, к чему ведёт размазывание определения поведения кода по большому числу разномастных файлов?
1) Тогда при чем здесь стек? (p.s. я про 21 век не в курсе, последнюю поделку на C++ ковырял лет 10 назад да и то неидеоматично)
2) Это компромисс — вы можете выбрать или самому или с сообществом поддерживать внешнее описание при этом получить поддержку nullability или забить. Для typescript сообщество поддерживает, полные описания типов для распространненных javascript библиотек, например http://definitelytyped.org/
1) Технические подробности реализации. В 99,995% случаев для современных плюсовиков они не важны.
2) Есть простая проблема: nullability требует специфического программирования. Как минимум, банальные проверки на null и выделение объектов. Конечно, в интерпретируемом языке такие проверки можно вносить извне на месте создания переменных, приравниваия или некоторых обращений, но это чистой воды костыль.
Я не говорю, что в них нет нужды, это даже несколько удобнее классических подходов, тем не менее, поддержка подобных проверок — Ад и Израиль, которую таже тимлиду врага не пожелаешь.
2) В Котлине есть специальные операторы чтобы это делать было удобно. Это компилируемый язык.
2.2) Сойдёмся на термине «транслируемый». Либо так, либо тысячи модов на майн не существуют. (Спойлер: они существуют). И, да, мне могут возразить «майн не на котлине написан». Но мне всё равно. Все жабошлюшки одинаковы, когда видят мой твёрдый decompiler.
2.1) Внешние аннотации подключаются к Java-коду, про Kotlin речи нет. Если в коде изначально нет защиты от null, её придётся вводить извне. И не важно, на стороне котлина или в дополнительных классах, резутьтат один.
2.2) Я не понял что вы написали.
2.1) Да. Просто в Котлине вы можете этим удобно воспользоваться + свой код аннотировать легко. Изначально данные аннотации были введены чтобы IDEA могла ими пользоваться и не модифицировать библиотеки. Если есть возможность их модифицировать, можно воспользоваться атрибутом
2.2) А вас не смущает возможность изменять поведение скомпилированного кода без внедрения специальных механизмов в этот самый код и само слово «скомпилированного» в одном предложении?
2.1) Это прекрасно! Восхитительно! ЭТО ШЕДЕВР!!1! Такой реакции вы от меня ждали? Ну вот, забирайте.
2.2) Никакого поведения скомпилированного кода не меняется — перечитайте описание. Меняется поведения компилятора при контроле типов при компиляции кусков которые используют этот код.
2.1) Пожалуй, подойдет "Восхитительно". Спасибо.
Пусть будет по-вашему. Несмотря на то, что у вас очень странное понимание термина «компиляция», с нездоровым JVM уклоном. Но да ладно.
У меня скорее с уклоном в абстрактное мышление :) совпадающее, впрочем, с точкой зрения авторов javaC, csC и прочих товарищей.
А clang — компилятор? Учитывая, что он компилирует в IR, который потом обрабатывается выбранным бэкендом и может закончить свою жизнь как в виде какого-нибудь условного байткода (wasm, asm.js), так и в виде бинарника.
Компиляция — трансляция программного кода из ЯП высокого уровня в ЯП низкого уровня или машинные коды. При компиляции чаще всего выполняются дополнительные оптимизации кода, не позволяющие произвести обратный процесс — декомпиляцию. Самое банальное — ликвидация строковых имён из кода: комментариев, названий переменных. Ликбез закончен.
Теперь, умник, расскажи мне 3 вещи.
1) Как это так получилось, что jar-файлы можно декомпилировать в практически изначальный код?
2) Что в термине «транслятор» не позволяет сводить 1024 внешних языка в своё внутреннее представление?
3) Каким местом clang будет внедрять внешние нотации, о которых изначально говорилось в https://habrahabr.ru/post/280075/#comment_8833366 пункт 2?

А пока не ответил, карму откатил. У меня из-за вас, каналий, подсветка синтаксиса в комментариях не работает, что очень неудобно при ведении дискуссий.
Теперь, умник, расскажи мне 3 вещи.

А пока не ответил, карму откатил. У меня из-за вас, каналий, подсветка синтаксиса в комментариях не работает, что очень неудобно при ведении дискуссий.

с нездоровым JVM уклоном

Для начала, не стоит хамить собеседникам.

Если же вернуться к вопросу что же такой компилятор, то в англоязычном сегменте обычно компилятор определяют как программу, которая транслирует исходный код на одном языке программирования в другой язык программирования, часто в asm или объектный код. Есть ещё source-to-source compiler'ы (transpiler'ы), которые компилируют из одного ЯП высокого уровня в другой ЯП высокого уровня. Например, RPython -> C или C -> JS (emscripten).
Когда мы будем в англоязычном сегменте, будем использовать англоязычные определения. Но мы пока не в англоязычном сегменте. Поэтому давайте использовать отечественные академические определения.
А они гласят, что компилятор — подмножество трансляторов. А clang — транслятор в LLVM и компилятор из LLVM в бинарики. Стандартная JVM — просто транслятор в байт-код с виртуальной средой выполнения. Чисто академически.

> Для начала, не стоит хамить собеседникам.
https://ru.wikipedia.org/wiki/Clang#.D0.9E.D0.B1.D0.B7.D0.BE.D1.80
Очень тяжело не хамить собеседникам, если они жонглируют терминами и влезают в середину диалога совершенно не в тему. Я был не прав, позволив себе сорваться. Однако ваши аргументы абсолютно не к месту.
Чисто академически JVM — виртуальная машина, использующая в качестве машинных кодов подготовленный компилятором байткод.
«Чистая декомпиляция» в java — миф. Если иерархия классов ещё сохраняется, то «декомпилированный» код и близко не стоит с оригиналом (если не брать самые простые вещи)…
Мы можем потратить пол-века, выясняя, «транслятор» или «компилятор». Притом, что из промежуточно собраных class файлов JVM подготавливает ещё и слинкованный оптимизированный байт-код.
Мне интересно не это. Можем ли мы говорить о полноценно скомпилированном коде, если в него можно на ходу встраивать другой код и даже менять поведение кода под капотом? Но да ладно. Меня утомили эти споры на пустом месте.
Можем ли мы говорить о полноценно скомпилированном коде, если в него можно на ходу встраивать другой код и даже менять поведение кода под капотом?

Ага, а фон-неймановской архитектуры и страниц памяти с правами rwx не существует, да. Или нативный код под amd64 не "полноценно скомпилированный"?
Очень тяжело не хамить собеседникам, если они жонглируют терминами и влезают в середину диалога совершенно не в тему. Я был не прав, позволив себе сорваться. Однако ваши аргументы абсолютно не к месту.

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


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

А использование термина "компилятор", являющегося калькой с английского вас не смущает?
А существование Jazelle, где байткод исполняется на голом процессоре?
> А использование термина «компилятор», являющегося калькой с английского вас не смущает?
Аргумент ниже пояса. У нас в толковом словаре для этого слова есть точно определённые значения. До тех пор, пока мы пишем на кириллице, мы используем именно эти значения. Не нравится, пишите термины на латинице, будем тянуть значения из оксфордского толковника.

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

> А существование Jazelle, где байткод исполняется на голом процессоре?
Он прям jar файл сжирает? Или ему нужно собрать программу в специальном формате?
А вас не смущает термин «JIT-компиляция», применяемый ко всем видам байт-кода? Интересно, что же происходит с «уже скомпилированным» байт-кодом во время этой самой компиляции?

> Ага, а фон-неймановской архитектуры и страниц памяти с правами rwx не существует, да. Или нативный код под amd64 не «полноценно скомпилированный»?
Внедрение в код с помощью только лишь xml-файла? Ну-ну, удачи.

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

> Заодно и на низкую карму жаловаться не придётся
Вам же приходится исходники без разметки читать, не мне. И ссылки без подсветки выделять. Я о ВАС, глупеньких, забочусь.
Он прям jar файл сжирает? Или ему нужно собрать программу в специальном формате?

А у вас процессор zip/tar.gz сжирает или требует специального формата? Если сделать ещё шаг — он ELF/PE сжирает или требует специального формата?

JAR — это просто zip-архив с метаинформацией. Можно его распаковать и собрать classpath руками или программно (как делают те же контейнеры, сама запускалка явы при использовании аргумента -jar/-cp).
А вас не смущает термин «JIT-компиляция», применяемый ко всем видам байт-кода? Интересно, что же происходит с «уже скомпилированным» байт-кодом во время этой самой компиляции?

Нет, не смущает. Компилируется в другое представление. Так же как компилятор, скажем Си может выдавать ассемблерный код, который будет ассемблироваться и линковаться далее.
Внедрение в код с помощью только лишь xml-файла? Ну-ну, удачи.

При чём здесь xml? То, что в некоторых библиотеках и тулзах это можно сделать xml'ем — всего лишь вопрос наличия библиотек. Реально всё делается на уровне генерации байткода другими библиотеками (javassist, asm) и загрузки класслоадером далее.

Никто не мешает в сишном или плюсовом коде подменять vtable после генерации нового бинарного кода тем же llvm. Или собирать .so/.dylib/.dll и использовать dlopen или его аналоги, как делает тот же Matlab. Если вам очень нужно — возьмите libxml2 и реализуйте аналогичное поведение. И, да, это написание своего рантайма. Так же народ делает свои модульные системы.
Вам же приходится исходники без разметки читать, не мне. И ссылки без подсветки выделять. Я о ВАС, глупеньких, забочусь.

Такими темпами это может перестать быть проблемой после достаточного минуса: будет сначала один комментарий в час, а потом и в сутки.
> При чём здесь xml?
https://www.jetbrains.com/help/idea/2016.1/external-annotations.html?origin=old_help
Я ничуть не сомневаюсь, что любой код может быть изменён на лету, было бы желание да привилегированный доступ. Разговор был о том, что IDEA позволяет внедрить в уже собранные библиотеки внешние нотации, дополнительные команды и, что немаловажно, внешние обработчики на другом ЯП.
Я упаду в ноги тому человеку, который позволит вот так вот просто на лету менять хотя бы просто тип переменной или входного параметра какой-либо функции какой-нибудь dll.
Вы уверены, что понимаете разницу между managed и unmanaged окружениями?
Есть что-нибудь, кроме виртуальной среды и, соответственно, виртуальной машины?
О, Господи, да кто ж спорит с тем, что можно патчить процессы? Усыпили, изменили память, разбудили, профит.
Ладно, я понял. Вы победили. Всё, забирайте свою лаврушку и и идите лапать фотомоделей.
Транслятор это вообще все, что переводит из одного языка в другой, компилятор — то, что переводит разом весь исходный текст сразу. Интерпретатор — то, что переводит по мере выполнения.
JVM — стековая машина она низкоуровневее чем язык Java. Например, в языке java нет обязяанности управлять стеком JVM вручную.
Читайте определения и прокачивайте асбстрактное мышление. Если у вас зеленая шапочка с помпоном это не значит, что все шапочки зеленые и у них обязательно должен быть помпон :)
> Компиляция — трансляция программного кода из ЯП высокого уровня в ЯП низкого уровня или машинные коды
Так вот же у вас тут написано: «в ЯП низкого уровня», т.е. например в байт-код. Да и в википедии такой пример приводится: ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BC%D0%BF%D0%B8%D0%BB%D1%8F%D1%82%D0%BE%D1%80#.D0.93.D0.B5.D0.BD.D0.B5.D1.80.D0.B0.D1.86.D0.B8.D1.8F_.D0.B1.D0.B0.D0.B9.D1.82-.D0.BA.D0.BE.D0.B4.D0.B0
К тому же, как ниже упомянули, jvm байт-код может исполняться на реальной железной машине, т.е. является в этом смысле машинными кодами.
Совсем недавно я был ярым противником default implementation в интерфейсах C#.
Но вот поглядишь как в Java сообществе обсуждают очевидно удобные и давно реализованные для C# вещи — и иначе начинаешь воспринимать развитие любимого языка (да и вообще любое развитие).
Это крайне иронично, но и заставляет задуматься, что очень полезно, спасибо.
Only those users with full accounts are able to leave comments. Log in, please.