Pull to refresh
38
0
Роман Кашицын @roman_kashitsyn

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

Send message
На самом деле мне после опыта функциональных и динамических языков очень часто не хватает интерпретатора, иногда хочется поиграться со своим кодом, вообще избежав компиляции :)
ООП-изм головного мозга создателей Java очень многих удручает. Мне также сильно не хватает простых человеческих функций, не связанных неестественными узами ООП. C++ — мультипарадигменный, позволяет выбирать ту парадигму, которая наиболее подходит в конкретной ситуации. И это, я считаю, очень разумно.
Потребность в изменяемых входных параметрах лично у меня возникает редко (есть способ их имитации через массив с одним элементом, но это скорее хак). Enum и foreach появились достаточно давно, ещё во времена 1.5, т. е. ~9 лет назад. Enum-ы, кстати, в java весьма замечательные.

В C# гораздо больше синтаксического сахара. За это его кто-то больше любит, кто-то наоборот. Я воздерживаюсь, отношусь к обоим понимающе.

Эккеля не читал, поэтому все совпадения случайны, я описываю лишь свой собственный опыт. Переносимость модулей — абсолютная реальность, просто Android — это не совсем Java, у него своя экосистема (поэтому, собственно, Oracle судился с Google). В секторе бизнес и веб-приложений (т.е. java SE и java EE) всё прекрасно переносится: код, скомпилированный на одной машине и ОС прекрасно живёт на других машинах и ОС без перекомпиляции.
У Java всё есть определённые преимущества перед C++: переносимый байт-код, что позволяет распространять модули в собранном виде (да и вообще относительно легко построить модульную систему), практическое отсутствие Undefined Behavior, быстрая компиляция, наличие рефлексии, развитая инфраструктура, тысячи хороших протестированных библиотек. Но толковых шаблонов, конечно, не хватает.

Много писал на Java, немного на C#. Как язык C# неплох и местами удобней Java, но инфраструктура мне, честно говоря, не очень нравится. Для java есть хорошие бесплатные IDE, отличные инструменты вроде maven и gradle, куча открытых отличных библиотек. Мне кажется, инфраструктура и распространённость Java выигрывает у C#. Да и из Linux работать с Java как-то проще. Но это субъективные ощущения, с этим можно поспорить при наличии адекватной статистики.
А я таки внял гласу Столлмана и начал осваивать емаксовый GNUS для работы с RSS. На эту страницу перешёл уже с него :)
Erlang совсем не сложный язык (не сравнить с C++, Haskell или Scala), да и в OTP ничего сложного нет. Очень маловероятно, что причиной выбора Go было неосиляторство.
долгая перекомпиляция тоже не радует
Мне всегда казалось, что компилятор java очень быстрый (особенно, по сравнению с c/c++). Ведь он не требует повторных запусков, самостоятельно разрешая зависимости на уровне кода и кешируя информацию о уже скомпилированных классах. Думаю, большую часть сборки вашего приложения занимает maven и многократная архивация, ведь java-инфраструктура использует архивы в архивах.
К примеру, собирал как-то java-порт BerkelyDB. В нём около тысячи классов, а ant собрал всё на моей не особо мощной машине за ~11 сек.
или сомневающийся невежда
hot fix для Haskell:

orElse = flip fromMaybe
process req = (liftM toJsonResponse $ getParam "id" req >>= findModelById) `orElse` NotFound

В этот раз Scala понятнее и лаконичнее получилось.
Nullable ближе, но не вижу в нем особых преимуществ.
Да, Nullable сам по себе не очень интересен и даёт лишь возможность представить отсутствие значения. Однако при наличии должной поддержки со стороны языка и библиотек монадический код с Maybe становится весьма приятным.

Псевдо-код на Scala:
def process(req: HttpReq): HttpResp =
    req.param("id").flatMap( Model.byId ).map( toJsonResponse ).getOrElse( NotFound )

Псевдо-код на Haskell:
import Control.Monad (liftM)
import Data.Maybe (fromMaybe)

process :: HttpReq -> HttpResp
process req = fromMaybe NotFound $ getParam "id" req >>= findModelById >>= liftM toJsonResponse 
Да, понятно, с классами такое не прокатит. Спасибо.
Nullable есть, просто методы писались ещё до его введения.
Кажется, вы промахнулись постом
Я понял вас, но всё же считаю, что тесты (на текущем уровне их развития) вообще не могут выступать в качестве полной спецификации. Если автор c++ функции утверждает, что она не бросает исключений, легко ли будет проверить это юнит тестами в общем случае?

Тесты всегда покрывают лишь часть всевозможных сценариев взаимодействия, и даже при наличии 100% покрытия тестами нельзя гарантировать, что рефакторинг действительно не изменил внешнего поведения. Они просто делают нас немного уверенней в этом факте. Кроме того, редко кто пишет тесты на ожидания кол-ва потребяемой памяти и ассимптотику алгоритмов, а ведь это, по сути, неотъемлимая часть «внешнего поведения».

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

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

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

IMHO, только с тестами можно спать спокойно по ночам после рефакторинга.
Нет, прогрессбара нет :)
Внешний вид процесса компиляции при использовании make-бэкэнда напоминает компиляцию Linux-ядра, судя по генерируемым Make-файлам, техника отображения выполняемых команд позаимствована именно оттуда (она также описана в книжке «Managing Projects with GNU Make» 3ed).
Я вас полностью поддерживаю. Я не ставил своей целью переубедить людей использовать CMake, я и сам долго колебался, какую из двух систем выбрать для проекта. Мне хотелось показать неплохую альтернативу и, заодно, подготовить публично доступную русскоязычную документацию по проекту (в частности, для моих коллег).
К сожалению, я не нашёл прямого аналога. Вообще возможности конфигурирования в GYP мне показались значительно более скудными, чем у CMake. Фактически, они ограничиваются секцией conditions, позволяя включать/исключать исходный код, флаги компиляции и линковки в зависимости от операционной системы и переменных.

Видимо, авторы GYP нацеливались на self-contained проекты, которые не интегрируются с окружением, а лишь выбирают наиболее подходящую реализацию своего функционала в зависимости от окружения. Но это лишь мои домыслы.
Кажется, теперь я понял, что моих проблем у вас просто не возникло. Когда проект один, с модулями всё довольно просто: они «знают», где лежат зависимости.

В моём случае есть линейка продуктов, или даже один продукт, состоящий из нескольких проектов (располагающихся в разных репозиториях). В таких условиях очень хочется повторно использовать одни и те же модули в разных продуктах и проектах, держать их в отдельных репозиториях и назначать им их собственные версии, встраивая в проект через некий механизм вроде svn:externals.
Вот тут как раз возникает вопрос: где должны быть зависимости модуля, чтобы модуль можно было собрать и отдельно, и в рамках всего проекта…

В любом случае, спасибо за ответ.

Information

Rating
Does not participate
Location
Zürich, Zürich, Швейцария
Date of birth
Registered
Activity