stdray: (Default)
stdray ([personal profile] stdray) wrote2012-11-07 08:03 pm

А почему макросам не радуются?

[personal profile] xeno_by написал, что макры для скалы почти вот-вот будут готовы. А люди как-то не очень радуются. Я почитал комментарии, мне что-то не понравилось такое обсуждение.


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

Во-первых, тут явно подразумевается, что кодогенерация является чем-то плохим и доказывает несостоятельность языка, как средства для написания программ. Из моего ежедневного: редактировать форму мне удобней в графическом дизайнере, просматривать схему базы данных и редактировать связи между таблицами опять же удобней в графическом представлении. По-моему, очевидно, что если существуют разные способы выполнить одну работу, то надо выбирать самый удобный. И либо у нас есть серебряная пуля, либо для каждой задачи существует свой самый удобный инструмент. А чтобы это все как-то между собой взаимодействовало о совмещалось, надо приводить к одному знаменателю. Например, к текстовому представлению в виде кода на определенном языке программирования. Этот способ не единственный, но, на мой взгляд, достаточно практичный и удобный.
Во-вторых, языки развиваются и видоизменяются. При этом во время компиляции многие известные мне языки сначала рассахариваются в некоторое подмножество языковых конструкцию, после чего код на этом подможестве преобразуется в AST и поехало. Специальный синтаксис для монад (linq query syntax в C#, do-нотация в Haskell), asyc/await в C#, сахар для стрелок в том же Haskell, препроцессоры OCaml и множество других примеров. Интересно, нормально ли после каждого релиза с подобными изменениями, упрекать авторов в том, что их язык оказался недостаточно хорош?

В-третьих, существуют расширения компилятора. Для Haskell'а они активно используются и даже можно встретить мнения, что часть этих расширений пора включить в стандарт. Для C# делается некий проект Roslyn, который должен позволить пилить аналогичным образом расширения для главного языка дотнетов. На мой взгляд, это свидетельсво того факта, что разные люди по-разному видят развитие инструмента и работают в соответствующем направлении. Расширение его возможностей или наоборот специализация - это нормально. Но можно, например, заявить про признание поражения.

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


Код с макросами очень трудно отлаживать.

Этот пойт я не понял. Я пишу на Немерле, и код с использованием макросов в отладке ни чем не отличается от кода без них. Откуда могут быть проблемы? Было выражение, потом на этапе компиляции оно раскрылось в другое выражение. И итоге получается простой линейный код с нормальными именами переменных. Проблемы - это когда стираются имена аргументов, когда стейт шарится между кучей объектов, когда стектрейс растягивается на два экрана, когда куча всего вычисляется лениво и ошибки этих вычислений экранируются и игнорируются или пихаются в стейт, когда все это вычисляется в нескольких потоках наступает ад. Макросы ничего в этот список не привносят. Есть еще отладка самих макросов, но это дело скорее неудобное чем сложное, по крайней мере, применительно к Немерле.


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

Во-первых, всем всем равно, чем занимается контингент именуемый здесь "индийские братья по разуму". Сколько лет я программирую, столько лет слышу эти рассказы, иногда вижу какие-то подтверждения. Если человек склонен к превращению кода в ад, он это сделает. Они этим занимались на Lisp, занимались на Си, занимаются на Java, будут заниматься на любом другом языке. (Я считаю, что в той или иной мере мы все к этому склонны, просто не всегда рядом есть кто-то, способный увидеть сумасшествие и указать на это, как и не всегда есть желание обсуждать подобное. А вопрос как раз и состоит в постоянном развитии и совершенствовании. И приоритеты в этом развитии могут быть разными).

Во-вторых, я не вижу, чтобы слабые программисты лезли использовать мощные и сложные средства. То есть существует некий контингент постоянно стремящийся интегрировать в проекты НОВЬЕ из последнего выпуска журнала Хакер или статей на Хабре, но там либо старшие товарищи останавливают, либо все желание пропадает, пока новатор разбирается с новой игрушкой. А те программисты, которые ничем не интересуются, пишут на небольшом примитивных подмножестве языка, мирно делаю свои велосипеды и никому жизнь портить не пытаются. (Всегда забавляет эта ежемесячная статья на Хабре "Что такое атрибуты в дотнете и зачем они нужны" и куча комментариев вроде "интересно, спасибо, прочитал") А макросы в статически типизируемом языке с негомоиконичным синтаксисом - штука сложна, очень сложная. И вроде, [personal profile] xeno_by говорил, мол Мартин считает, что макросы и должны быть сложными. Может по каким-то таким причинам.


Скала очень сложная и без макросов.

- Ребята, я конфетки вам принес
- Не надо, у нас уже есть БАГЕТ. Очень сытный


То есть, я каким-то серьезных аргументов против макросов в Скале пока не увидел. Не хотят люди пользоваться - никто не заставляет. Не знают, какие задачи будут решаться макросами - но ведь никто и не спрашивает. Да и часто не читают про эти самые макросы, то у там С++, то сишка, то рефлексия тормозит.

[identity profile] jdevelop.livejournal.com 2012-11-07 06:37 pm (UTC)(link)
у меня смутное подозрение, что вы никогда не отлаживали код на скале или там кложури

пример

с макросами такие вот трейсы отлаживать будет не то, чтобы сложно, а сложно в сотой степени двойки. Потому что у меня в исходном коде даже и строки такой не будет, на которой оно уебется в говно, и нужно будет чесать репу - a$b$c at Source.scala:110 при общем количестве строк в Source.scala в 20 - это куда смотреть?

так понятнее?

[identity profile] xeno-by.livejournal.com 2012-11-07 06:46 pm (UTC)(link)
Я уже упоминал, что макросы в Скале не текстовые. Соответственно, можно догадаться, что номера строк в сырцах они разрушать не будут. А еще просто можно взять, попробовать и убедиться.

[identity profile] thesz.livejournal.com 2012-11-07 08:08 pm (UTC)(link)
Они легко могут добавить некоторые дополнительные действия, не имеющиеся в исходном тексте. Оптимизированную программу отладчиком VS отлаживать трудно, что говорить про улучшения на коленке в виде макросов.

"Попробовать и убедиться" - увольте. Я уже неоднократно говорил, что Scala не подходит для эффективной работы, особенно в функциональном стиле. Вот начнут компилировать в нативный код, чтобы объекты занимали ровно столько, сколько нужно, тогда и посмотрим. Если смогут, конечно.

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

[identity profile] xeno-by.livejournal.com 2012-11-07 08:20 pm (UTC)(link)
Про действия согласен. С этим предлагается бороться вот как.

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

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

Про "попробовать и убедиться" я предлагал уважаемому [livejournal.com profile] jdevelop в плане убедиться в том, что строки не разъезжаются от раскрытия макросов.

[identity profile] thesz.livejournal.com 2012-11-07 09:00 pm (UTC)(link)
>Тогда дебаггер сможет по этой информации воссоздать исходник с раскрытыми макросами, и отладка будет вестись как будто этот исходник был вручную написан программистом.

К TurboAssembler прилагался отличный отладчик. Он назывался td.exe. ТурбоДебаггер. А ещё был td386.exe, который позволял использовать больше памяти MS-DOS.

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

[identity profile] golikov konstantine (from livejournal.com) 2012-11-08 01:50 am (UTC)(link)
>вот начнут компилировать в нативный код

так уже же

есть scala под llvm, его конечно надо потыкать палочкой что бы убедится что оно живое, но как proof-of-concept вполне годится

[identity profile] thesz.livejournal.com 2012-11-08 09:26 am (UTC)(link)
Этого мало самого по себе. Надо, чтобы накладные расходы на значения были в районе одного слова.

А то компилирующаяся в машинный код Scala будет иметь все минусы - и большие накладные расходы, и трудности с библиотеками.

[identity profile] sassa-nf.livejournal.com 2012-11-08 10:08 am (UTC)(link)
я эту линию дискуссии не понимаю. В итоге вся скала компилируется JITом в машинный код. Беда в том, что JIT не силён в разворачивании обёрток, в которые вычисления завёрнуты.

Ленивые значения в Хаскеле как считать - одно значение в районе одного слова или это thunk в районе одного слова+одно значение?

[identity profile] thesz.livejournal.com 2012-11-08 11:29 am (UTC)(link)
Вот пример (я его уже неоднократно приводил).

http://hackage.haskell.org/packages/archive/containers/0.1.0.1/doc/html/src/Data-IntSet.html#IntSet

Значение с конструктором Tip займет два слова. Значение с конструктором Bin займёт 5 слов. Bin, как легко понять, вдвое меньше, чем Tip. В среднем, получится 3.5 слов на значение. В Java не получится лучше, чем 4,5 слов на значение.

Сколько слов займут эти два конструктора в Скале?

(no subject)

[identity profile] sassa-nf.livejournal.com - 2012-11-08 13:08 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-08 13:25 (UTC) - Expand

(no subject)

[identity profile] sassa-nf.livejournal.com - 2012-11-08 13:48 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-08 13:57 (UTC) - Expand

(no subject)

[identity profile] sassa-nf.livejournal.com - 2012-11-08 14:39 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-08 14:46 (UTC) - Expand

(no subject)

[identity profile] sassa-nf.livejournal.com - 2012-11-08 14:58 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-08 15:03 (UTC) - Expand

(no subject)

[identity profile] sassa-nf.livejournal.com - 2012-11-08 15:23 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-08 16:00 (UTC) - Expand

(no subject)

[identity profile] sassa-nf.livejournal.com - 2012-11-08 16:10 (UTC) - Expand

[identity profile] jdevelop.livejournal.com 2012-11-07 08:58 pm (UTC)(link)
они НЕ МОГУТ не разрушать номера строк, по определению. Это привнесенные куски кода.

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

403 did not equal 404
org.scalatest.exceptions.TestFailedException: 403 did not equal 404
	at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:320)
	at animatron.restful.service.AuthenticationSvcTest.newAssertionFailedException(AuthenticationSvcTest.scala:34)
	at org.scalatest.Assertions$class.assert(Assertions.scala:411)
	at animatron.restful.service.AuthenticationSvcTest.assert(AuthenticationSvcTest.scala:34)
	at animatron.restful.service.AuthenticationSvcTest$$anonfun$7$$anonfun$apply$mcV$sp$5.apply$mcV$sp(AuthenticationSvcTest.scala:140)
	at animatron.restful.service.AuthenticationSvcTest$$anonfun$7$$anonfun$apply$mcV$sp$5.apply(AuthenticationSvcTest.scala:140)
	at animatron.restful.service.AuthenticationSvcTest$$anonfun$7$$anonfun$apply$mcV$sp$5.apply(AuthenticationSvcTest.scala:140)
	at scala.util.DynamicVariable.withValue(DynamicVariable.scala:57)
	at spray.testkit.RouteTest$$anonfun$check$1.apply(RouteTest.scala:44)
	at spray.testkit.RouteTest$$anonfun$check$1.apply(RouteTest.scala:44)
	at spray.testkit.RouteResultComponent$RouteResult.$tilde$greater(RouteResultComponent.scala:109)
	at animatron.restful.service.AuthenticationSvcTest$$anonfun$7.apply$mcV$sp(AuthenticationSvcTest.scala:139)
	at animatron.restful.service.AuthenticationSvcTest$$anonfun$7.apply(AuthenticationSvcTest.scala:133)
	at animatron.restful.service.AuthenticationSvcTest$$anonfun$7.apply(AuthenticationSvcTest.scala:133)
	at org.scalatest.FlatSpec$$anon$1.apply(FlatSpec.scala:2987)
	at org.scalatest.Suite$class.withFixture(Suite.scala:1994)
	at animatron.restful.service.AuthenticationSvcTest.withFixture(AuthenticationSvcTest.scala:34)
	at org.scalatest.FlatSpec$class.invokeWithFixture$1(FlatSpec.scala:2984)
	at org.scalatest.FlatSpec$$anonfun$runTest$1.apply(FlatSpec.scala:2993)
	at org.scalatest.FlatSpec$$anonfun$runTest$1.apply(FlatSpec.scala:2993)
	at org.scalatest.SuperEngine.runTestImpl(Engine.scala:228)
	at org.scalatest.FlatSpec$class.runTest(FlatSpec.scala:2993)
[100500 lines skipped]


почему-то оно сначала уебалось на строке с декларацией класса, потом уже в нужном месте

тестовый код при это выглядит как:

133:  "AuthenticationService" should "fail on wrong password" in {
134:    val user = route.signup.createAccount(
135:      new EmailPasswordCredentials("123@123.com", "password"),
136:      "Jane Fox",
137:      "http://google.com")
138:    val content = new EmailPasswordCredentials("123@123.com", "passwordd")
139:    Post("/authenticate", content) ~> route.authenticate ~> check {
140:      assert(status.value === 404)
141:    }
  }


и никаких макросов, но ПЕРВЫМИ строчками в трейсе идет какой-то аццкий буллшит. При Сталине Гослинге такого не было. Я читаю эти имена функций в трейсе и мне натурально становится жалко тех людей, которым не дай бог придется это поддерживать

Теперь взять эти макросы - они сделают все только хуже и еще более нечитабельнее в плане трейсов.
Edited 2012-11-07 21:17 (UTC)

[identity profile] sassa-nf.livejournal.com 2012-11-07 09:28 pm (UTC)(link)
совершенно согласен. Здесь мы имеем дело с идентичной проблемой: скала нагенерировала туеву хучу кода, который я не писал, и узнать взаимодействие кучи пронумерованных $$anonfunction$$ невозможно.

[identity profile] jdevelop.livejournal.com 2012-11-07 09:55 pm (UTC)(link)
это проблема натягивания совы на глобус - перекладывание функционального программирования на не приспособленную для него никак вообще JVM

scala была бы ок, если бы собиралась в нативный код, или если бы у неё была своя VM, как у хаскеля.

[identity profile] sassa-nf.livejournal.com 2012-11-07 11:13 pm (UTC)(link)
хаскель стек трейсы печатает?

господибожемой про JVM не комментирую

(no subject)

[identity profile] sassa-nf.livejournal.com - 2012-11-08 01:13 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-08 09:33 (UTC) - Expand

(no subject)

[identity profile] sassa-nf.livejournal.com - 2012-11-08 09:57 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-08 10:12 (UTC) - Expand

(no subject)

[identity profile] sassa-nf.livejournal.com - 2012-11-08 11:06 (UTC) - Expand

(no subject)

[identity profile] thesz.livejournal.com - 2012-11-08 11:50 (UTC) - Expand

(no subject)

[identity profile] sassa-nf.livejournal.com - 2012-11-08 12:51 (UTC) - Expand

[identity profile] golikov konstantine (from livejournal.com) 2012-11-08 01:54 am (UTC)(link)
specs2 кстати вроде бы таким не страдает, хотя могу ошибаться

[identity profile] metaclass.livejournal.com 2012-11-08 05:04 am (UTC)(link)
Кстати, насчет номеров строк ты не совсем прав. Их можно сохранить в отладочную информацию до раскрытия макросов и так и оставить.
В C# и С++ для этого #line есть или как там его, в жабе не знаю.
Если по хорошему - то надо указывать два номера строки - до раскрытия и после раскрытия, вплоть до вкручивания оригинальных номеров внутрь манглинга имен. :)

[identity profile] stdray.livejournal.com 2012-11-07 07:20 pm (UTC)(link)
>с макросами такие вот трейсы отлаживать будет не то, чтобы сложно, а сложно в сотой степени двойки.

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

Игрушечный пример.

Макрос for

for(mutable i=0; i< 100; i++) {
      WriteLine(i);
}

раскрывается вот в такое представление (показан уже типизированный код)
{
  mutable i = 0;
  ((_N_break :
  {
    def loop ()   : void
    {
      match ((i < 100 : bool))
            {
        | true =>
          (
          {
            ((_N_continue :
            {

              {
                WriteLine(i)
              }
            }) : void );

            {
              [[Cache:i]]
              ;
              [[CacheRef:i]] = _N_op_Increment([[CacheRef:i]])
            };
            loop()
          } : void )
        | _  =>
          ()
      }
    };
    loop()
  }) : void )
}


Отлаживается оно самым обычным привычным образом и со строчками никакой неразберихи нет.
Image (http://img528.imageshack.us/img528/6129/debugmacro.png)
Edited 2012-11-07 19:47 (UTC)

[identity profile] jdevelop.livejournal.com 2012-11-07 08:57 pm (UTC)(link)
ок, еще раз

20:    for(mutable i=0; i< 100; i++) {
21:        WriteLine(i);
22:    }


дальше по развернутому коду оно скажем упарывается в строке 45, хотя по факту упоролось в строке 21.

как я об этом догадаюсь?

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

[identity profile] sassa-nf.livejournal.com 2012-11-07 09:26 pm (UTC)(link)
совершенно справедливо. в таких случаях необходимо, чтобы top-level exception указывал 21, а caused by настоящий стектрейс развёрнутого макроса.

[identity profile] jdevelop.livejournal.com 2012-11-07 09:31 pm (UTC)(link)
да, на таких условиях я согласен с макросами, пусть будут

еще я бы очень хотел, чтобы писатели языков не думали о монадах, стрелках клейсли, генераторах компиляторов, а посмотрели на тот пиздец, что у них твориться в трейсах и придумали как бы этого избежать и включать в него АКТУАЛЬНЫЕ данные по исходному коду, который писал программист. А не весь тот матан, нагенерированный компилятором.

[identity profile] thedeemon.livejournal.com 2012-11-08 03:16 am (UTC)(link)
У них другой подход: не доводить до стектрейса, а еще на этапе компиляции заявить "ваша монада не коммутирует!"

[identity profile] stdray.livejournal.com 2012-11-07 10:44 pm (UTC)(link)
В эксепшоне в стэктрейсе будет указана строка 21. Потому что сколько бы там всего хорошего не нагенерил макрос, все это произошло в именно в строке строке его вызова. Чтобы показывать "настоящий" стектрейст развернутого макроса, надо где-то иметь файлы, куда дампается ast после раскрытия всех макросов. Я думаю, это осуществимо, может в немерле даже сделано, просто я не в курсе. Но из самой концепции квазицитирования ничего подобного не следует, поскольку объектом преобразования является ast, а не текстовый файл с кодом.

[identity profile] jdevelop.livejournal.com 2012-11-08 09:57 am (UTC)(link)
это слишком хорошо, чтобы быть правдой

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

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

на этом месте техподдержка может засверлиться монадой

[identity profile] stdray.livejournal.com 2012-11-08 10:27 am (UTC)(link)
Я ничего не могу сказать про сложность отладки Скалы, поскольку не пишу на ней. Я только чуть-чуть в защиту макросов, потому как более-менее активно пишу на Немерле, где очень многое реализуется макрами, и читаю бумаги, которые выкладывает xeno_by.

(no subject)

[identity profile] jdevelop.livejournal.com - 2012-11-08 12:54 (UTC) - Expand

(no subject)

[identity profile] stdray.livejournal.com - 2012-11-08 13:11 (UTC) - Expand

[identity profile] stdray.livejournal.com 2012-11-08 10:29 am (UTC)(link)
>внезапно, программы могут быть у кастомера, доступ на отладку может быть только через высылание куска логов

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