Язык программирования для самоизменения кода?

Рассматривали ли вы кодировку JSON? Если вы сконфигурируете свой KafkaProducer с параметром value_serializer следующим образом:

KafkaProducer(value_serializer=lambda v: json.dumps(v).encode('utf-8'))

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

producer.send('test', [1, 2, 3])
producer.send('test', ["cat", "dog", "fish"])

Потребители должны быть настроены на декодировать через JSON, а также. Если вы используете kafka-python, вы можете сделать что-то вроде:

KafkaConsumer(value_deserializer=lambda v: json.loads(v.decode('utf-8')))
34
задан Luke Miles 26 February 2019 в 01:27
поделиться

13 ответов

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

(*) Отказ от ответственности: на самом деле это может быть не весело.

46
ответ дан 27 November 2019 в 16:00
поделиться

Внедрение Длэнга LLVM содержит @dynamicCompile и признаки функции @dynamicCompileConst, позволяя Вам собрать по словам хозяина по рождению набор команд во время компиляции и константы времени компиляции изменения во времени выполнения посредством перекомпиляции.

https://forum.dlang.org/thread/bskpxhrqyfkvaqzoospx@forum.dlang.org

0
ответ дан 27 November 2019 в 16:00
поделиться

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

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

4
ответ дан 27 November 2019 в 16:00
поделиться

Все ответы на данный момент касаются компиляции отражения / времени выполнения, но в комментариях, которые вы упомянули, вас интересует фактический самомодифицирующийся код - код, который модифицируется в памяти.

Невозможно сделать это в C #, Java или даже (переносимо) в C - то есть вы не можете изменить загруженный двоичный файл в памяти, используя эти языки.

В общем, единственный способ сделать это - сборка, и она сильно зависит от процессора. Фактически, он также сильно зависит от операционной системы: для защиты от полиморфных вирусов большинство современных операционных систем (включая Windows XP +, Linux и BSD) применяют W ^ X , что означает, что вам придется столкнуться с некоторыми проблемами , чтобы написать полиморфные исполняемые файлы в этих операционных системах, для тех, которые позволяют это вообще.

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

15
ответ дан 27 November 2019 в 16:00
поделиться

Могу я предложить Python , хороший высокоуровневый динамический язык с богатым самоанализом (и, например, с использованием compile , eval или exec разрешает форму самомодифицирующегося кода). Очень простой пример, основанный на вашем вопросе:

def label1(a,b,c):
    c=a+b
    return c

a,b,c=10,20,0    
print label1(a,b,c) # prints 30

newdef= \
"""
def label1(a,b,c):
    c=a*b
    return c
"""
exec(newdef,globals(),globals())

print label1(a,b,c) # prints 200

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

9
ответ дан 27 November 2019 в 16:00
поделиться

Вы смотрели Java? Java 6 имеет API компилятора , поэтому вы можете писать код и компилировать его в Java VM.

0
ответ дан 27 November 2019 в 16:00
поделиться

Это можно сделать в Maple (язык компьютерной алгебры). В отличие от тех многих ответов выше, которые используют скомпилированные языки, которые позволяют вам создавать и связывать в новый код во время выполнения, здесь вы можете честно изменить код выполняющейся в настоящее время программы. (Ruby и Lisp, как указали другие респонденты, также позволяют вам это делать; возможно, Smalltalk тоже).

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

Как указывали другие: для этого вам нужен интерпретируемый язык с сильными средствами рефлексии и материализации.

Я написал автоматический нормализатор / упрощатель для кода Maple, который я начал выполнять для всей библиотеки (включая ее самого); и поскольку я не был слишком осторожен со всем своим кодом, нормализатор изменил себя. Я также написал Partial Evaluator (недавно принятый SCP) под названием MapleMIX - доступный на sourceforge - но не смог полностью применить его к себе (это не было целью дизайна).

1
ответ дан 27 November 2019 в 16:00
поделиться

Common Lisp был разработан с учетом такого рода вещей. Вы также можете попробовать Smalltalk , где использование отражения для изменения выполняемого кода не является чем-то неизвестным.

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

7
ответ дан 27 November 2019 в 16:00
поделиться

Лично мне кажется довольно странным, что вы считаете ассемблер более простым в обращении, чем C#. Мне кажется еще более странным, что вы считаете ассемблер не таким мощным: вы не можете быть более мощным, чем сырой машинный язык. В любом случае, каждому свое.

В C# есть отличные сервисы отражения, но если у вас есть неприязнь к этому... Если вам действительно удобно работать с C или C++, вы всегда можете написать программу, которая пишет C/C++ и отдает ее компилятору. Это было бы жизнеспособно, только если ваше решение не требует быстрого времени самопереписывания (порядка десятков секунд или больше).

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

10
ответ дан 27 November 2019 в 16:00
поделиться

Многие языки позволяют вам eval код во время выполнения .

  • Lisp
  • Perl
  • Python
  • PHP
  • Ruby
  • Groovy (через GroovyShell)
6
ответ дан 27 November 2019 в 16:00
поделиться

Я очень рекомендую Lisp. Данные Лиспа можно читать и выполнять как код. Код на Лиспе можно записать как данные.

Он считается одним из канонических самомодифицируемых языков.

Пример списка (данные):

'(+ 1 2 3) 

или вызов данных в виде кода

(eval '(+ 1 2 3)) 

запускает функцию +.

Вы также можете входить в списки и редактировать их "на лету".

edit:

Я написал программу для динамического создания программы и оценки ее на лету, а затем доложил мне, как она работает по сравнению с базовой линией (div на 0 был обычным отчетом, ха).

23
ответ дан 27 November 2019 в 16:00
поделиться

В Lua вы можете "подцеплять" существующий код, что позволяет вам присоединять произвольный код к вызовам функций. Это происходит примерно так:

local oldMyFunction = myFunction
myFunction = function(arg)
    if arg.blah then return oldMyFunction(arg) end
    else
        --do whatever
    end
end

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

0
ответ дан 27 November 2019 в 16:00
поделиться

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

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

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

class Cache
  def [](key)
    @backing_store ||= self.expensive_initialization

    def [](key)
      @backing_store[key]
    end

    @backing_store[key]
  end
end

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

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

РЕДАКТИРОВАТЬ: Теперь, когда я думаю об этом, эта оптимизация не имеет большого смысла. В любом случае дорогостоящая инициализация выполняется только один раз. Единственное, чего избегает модификация, - это условности. Лучше взять пример, где сам чек стоит дорого, но я не могу придумать ни одного.

Однако я подумал о классном примере самомодифицирующегося кода: Maxine JVM . Maxine - это исследовательская виртуальная машина (технически не разрешено называть «JVM», потому что ее разработчики не запускают наборы тестов совместимости), полностью написанная на Java. Сейчас существует множество JVM, написанных сама по себе, но Максин - единственная, о которой я знаю, которая также запускает сама по себе. Это очень мощно. Например, JIT-компилятор может JIT-компилировать себя, чтобы адаптировать его к типу кода, который он компилирует JIT.

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

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

2
ответ дан 27 November 2019 в 16:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: