Re[4]: Решение на Ruby DSL.
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 27.02.06 16:47
Оценка:
Здравствуйте, Oyster, Вы писали:

O>Спасибо за код. Я так понял, что Ruby — язык с динамической типизацией?


Да.

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


Уж не знаю... С сишными макросами ничего общего.
На счет невнятности сообщений об ошибках: попробовал сейчас сделать синтаксическую ошибку в методе generate, убрал закрывающую скобку в конструкторе. Получил такое сообщение:
t3.rb:37:in `object': (eval):7:in `object': compile error (SyntaxError)
(eval):6: syntax error  from t3.rb:41:in `eval'
        from t3.rb:37:in `object'
        from t3.rb:41

(eval):7 -- это как раз место, где Ruby обнаружил синтаксическую ошибку (т.е. 7 -- это номер строки, которую обрабатывал eval). Если результат generate где-нибудь распечатать, то ошибка определяется достаточно точно.

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


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

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


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: Решение на Ruby DSL.
От: Oyster Украина https://github.com/devoyster
Дата: 27.02.06 16:54
Оценка: +1
Здравствуйте, eao197, Вы писали:

E>Уж не знаю... С сишными макросами ничего общего.


Я имею в виду принцип — сначала собираем код как текст, потом компилим (интерпретируем).

E>(eval):7 -- это как раз место, где Ruby обнаружил синтаксическую ошибку (т.е. 7 -- это номер строки, которую обрабатывал eval). Если результат generate где-нибудь распечатать, то ошибка определяется достаточно точно.


Да это-то понятно, что на ошибку в сгенерированном типе он укажет. Вот указал бы он на ошибку в макросе... но это просто невозможно при таком подходе.
Re[6]: Решение на Ruby DSL.
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 27.02.06 16:59
Оценка: +1
Здравствуйте, Oyster, Вы писали:

O>Да это-то понятно, что на ошибку в сгенерированном типе он укажет. Вот указал бы он на ошибку в макросе... но это просто невозможно при таком подходе.


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


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[4]: Решение на Ruby DSL.
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 27.02.06 17:20
Оценка:
Здравствуйте, Oyster, Вы писали:

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


Вот штука, которая должна позволять работать с Ruby AST: Parse Tree.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[7]: Решение на Ruby DSL.
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.03.06 19:46
Оценка:
Здравствуйте, eao197, Вы писали:


E>При таком подходе макросов, как таковых, нет.


Куда же они делись? Самые что ни наесть, но текстуальные. Именно это и роднит их с С. И это их основаня проблема.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Решение на Ruby DSL.
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 07.03.06 10:17
Оценка: 5 (1)
Здравствуйте, VladD2, Вы писали:

VD>Куда же они делись? Самые что ни наесть, но текстуальные. Именно это и роднит их с С. И это их основаня проблема.


Влад, макросы в C/C++ -- это средство, модифицирующее исходный код программы до его обработки компилятором. В Ruby выполняется динамическая трансляция исходного текста во внутреннее представление с последующим исполнением получившегося кода (фактически интерпритация). В таком подходе нет отдельной фазы разворачивания макросов перед трансляцией. Более того, например, декларация класса в Ruby -- это тот же самый код, который исполняется последовательно, что позволяет, к примеру, делать так:
class SomeClass
  if $debug_mode
    # Такой конструктор будет у класса, если работаем в отладке.
    def initialize( param1, param2, param3 )
      # ...
    end

    # Так же для отладки добавляется специальный метод.
    def debug_dump( debug_stream )
      # ...
    end
  else
    # В release у класса будет другой конструктор.
    def initialize( param )
      # ...
    end
  end
end

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

Как следствие этого, в Ruby можно сделать то, что в принципе невозможно сделать макросами C/C++ -- изменить код программы после трансляции.

Так что, никакие это не макросы, это особенность интерпритации кода.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[9]: Решение на Ruby DSL.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.03.06 15:04
Оценка:
Здравствуйте, eao197, Вы писали:

E>Влад, макросы в C/C++ -- это средство, модифицирующее исходный код программы до его обработки компилятором. В Ruby выполняется динамическая трансляция исходного текста во внутреннее представление с последующим исполнением получившегося кода (фактически интерпритация). В таком подходе нет отдельной фазы разворачивания макросов перед трансляцией.


Без разницы. Разница только в том на каком уровне работают макросы. На уровне текста, или на уровне АСТ.

E>Более того, например, декларация класса в Ruby -- это тот же самый код, который исполняется последовательно, что позволяет, к примеру, делать так:

E>
E>class SomeClass
E>  if $debug_mode
E>    # Такой конструктор будет у класса, если работаем в отладке.
E>    def initialize( param1, param2, param3 )
E>      # ...
E>    end

E>    # Так же для отладки добавляется специальный метод.
E>    def debug_dump( debug_stream )
E>      # ...
E>    end
E>  else
E>    # В release у класса будет другой конструктор.
E>    def initialize( param )
E>      # ...
E>    end
E>  end
E>end
E>


Ну, и в чем тут отличие от С? Замени if на #ifdef и ...

E>Фактически, исходный файл для Ruby-интерпритатора -- это исходный поток, из которого нужно извлекать очередную строку, транслировать ее во внутренее представление и исполнять. Поэтому совершенно нормальным является временная смена этого исходного потока на строку, сформированную самой программой.


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

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

E>Как следствие этого, в Ruby можно сделать то, что в принципе невозможно сделать макросами C/C++ -- изменить код программы после трансляции.


Это не заслука макроподсистемы. Это заслуга интерпретатора. В С++ моного нельзя того что можно в Руби. Но это уже ограничения подхода (статически типизированного языка).

E>Так что, никакие это не макросы, это особенность интерпритации кода.


То что ты показал — это макросы чистой воды. Причем худший их вариант.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Решение на Ruby DSL.
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.03.06 08:57
Оценка:
Здравствуйте, VladD2, Вы писали:

> Без разницы. Разница только в том на каком уровне работают макросы. На

> уровне текста, или на уровне АСТ.

Интересно. А что в твоем представлении является макросами?

> Ну, и в чем тут отличие от С? Замени if на #ifdef и ...


... и ты не понял. В декларации класса можно использовать любой код, хоть if-ы, хоть циклы. Вот, например:
class Demo
    FUNCS = { :strlen => 'int strlen(const char *str)',
        :strcpy => 'char * strcpy(char *to, const char *from)',
        :strcat => 'char * strcat(char *to, const char *from)' }

    FUNCS.each { |k, v| define_method( k ) { v } }
end

puts Demo.instance_methods( false )
puts "---------------"

d = Demo.new
puts d.strlen
puts d.strcpy
puts d.strcat


Производит:
strcat
strcpy
strlen
---------------
int strlen(const char *str)
char * strcpy(char *to, const char *from)
char * strcat(char *to, const char *from)


Как такое сделать в C с помощью директив компиляции?
А ведь можно еще и так написать:
FUNCS.each { |k, v| class_eval "def #{k}; '#{v}'; end" }


Результат будет тот же самый.

> Ключевое слово выделено. Формирование строк слишком подверженно ошибкам

> и имеет слишком слабый контроль.

О каких ошибках и о каком контроле ты говоришь?

> Плюс это полностью отрежает возможность

> получать информацию о типах.

Не понимаю.

> E>Так что, никакие это не макросы, это особенность интерпритации кода.

>
> То что ты показал — это макросы чистой воды. Причем худший их вариант.

Чем же это худший вариант? Обычная кодогенерация в run-time.
Просто в динамических языках работа идет по другому. Поэтому не нужно пытаться повесить на динамические языки ярлыки из статически-типизированных языков.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[9]: Решение на Ruby DSL.
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 13.03.06 09:44
Оценка:
Здравствуйте, eao197, Вы писали:

E> В Ruby выполняется динамическая трансляция исходного текста во внутреннее представление с последующим исполнением получившегося кода (фактически интерпритация). В таком подходе нет отдельной фазы разворачивания макросов перед трансляцией. Более того, например, декларация класса в Ruby -- это тот же самый код, который исполняется последовательно, что позволяет, к примеру, делать так:


Похоже на препроцессор. Я так понимаю, что два раза с разными параметрами такой код не вызвать?
http://www.smalltalk.ru | << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Re[10]: Решение на Ruby DSL.
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 13.03.06 10:14
Оценка: 5 (1)
Здравствуйте, Andrei N.Sobchuck, Вы писали:

ANS>Похоже на препроцессор. Я так понимаю, что два раза с разными параметрами такой код не вызвать?


Вызвать.
# Файл class_def.rb
class TestClass
  if $debug
    def debug_dump
    end
  else
    def release_mode
    end
  end

  def initialize
  end

  def hello_world
  end
end

# Файл t1.rb
$debug = true

load 'class_def.rb'

a = TestClass.new

puts "Step 1:\n" + a.class.instance_methods(false).join( "\n" ) + "\n-----"

$debug = false

load 'class_def.rb'

puts "Step 2:\n" + a.class.instance_methods(false).join( "\n" ) + "\n-----"


Запуск t1.rb на выполнение приводит к получению результата:
Step 1:
hello_world
debug_dump
-----
Step 2:
hello_world
release_mode
debug_dump
-----

Видно, что на втором шаге появился метод release_mode.

Комментарий: в Ruby классы являются открытыми, что позволяет расширять класс новыми методами уже по ходу работы программы. Именно поэтому на втором шаге появился метод release_mode. Но ранее определенные в классе методы просто так не исчезают, т.к. они уже были определены. Поэтому на втором шаге метод debug_dump остался в списке методов. Чтобы изъять метод debug_mode нужно было бы переписать определение класса так:
class TestClass
  if $debug
    def debug_dump
    end

    remove_method :release_mode if method_defined? :release_mode
  else
    def release_mode
    end

    remove_method :debug_dump if method_defined? :debug_dump
  end

  def initialize
  end

  def hello_world
  end
end

Тогда бы получили:
Step 1:
hello_world
debug_dump
-----
Step 2:
hello_world
release_mode
-----


Ну и еще симпатичнее это решение бы выглядело, если бы обращения к remove_method были бы упрятаны во вспомогательный метод remove_if_present:
class TestClass
  def self.remove_if_present( sym ); remove_method sym if method_defined? sym; end

  if $debug
    def debug_dump
    end

    remove_if_present :release_mode
  else
    def release_mode
    end

    remove_if_present :debug_dump
  end

  def initialize
  end

  def hello_world
  end
end


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[10]: Решение на Ruby DSL.
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.03.06 16:38
Оценка:
Здравствуйте, Andrei N.Sobchuck, Вы писали:

ANS>Похоже на препроцессор. Я так понимаю, что два раза с разными параметрами такой код не вызвать?


А в чем проблема препроцессор два раза прогнать?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.