gdb и conditional breakpoints
Думаю, что выражения в conditional breakpoints интерпретируются. Где мне это точно выяснить? Мне нужна ссылка для научной статьи.
Думаю, что выражения в conditional breakpoints интерпретируются. Где мне это точно выяснить? Мне нужна ссылка для научной статьи.
И как связаться с автором? Последний коммит 2 дня назад, но что в целом?
Смотрю в википедию, отличий не нахожу. Если так, то почему в википедии не упомянуты Си и Common Lisp?
Я встретил такое мнение (см. табличку в конце) : в Скале пытались уйти от проблемы ромба примесями, но примеси сами по себе могут образовывать ромб, поэтому ромб примесей в Скале административно запрещён. Выглядит, как будто сначала плохо подумали, а потом поставили заплату. Или я что-то не понял в жизни?
Иными словами, тогда зачем вообще примеси? Множественное наследование и композиция. Запрети ромб в множественном наследовании и получишь всё, что могут примеси, не вводя их отдельно. Пусть будут просто классами.
Вот программка на Хаскеле
sayMe :: (Integral a) => a -> String
sayMe x
| x <= 2 = "Less then three!"
sayMe 1 = "One!"
main = putStrLn (sayMe 1)
-- результат зависит от порядка определений
Эта штука мне нравится, поскольку по сути это тот «полиморфизм», который гениально прост и при этом не налагает никаких требований на систему типов. В С++ или в CLOS методы выбираются не по порядку определения, а по отношению «предок-потомок», или, иными словами «тип-подтип». Это отношение не всегда легко определить.
Но у меня вопросы:
1. Могу ли я размазать определение sayMe по нескольким модулям, ничего не знающим друг про друга?
2. Если да, то как при этом выстраивается порядок определений? Ведь обычно при сборке мы не точно знаем порядок впихивания модулей в готовый исполняемый файл.
3. Есть ли способ воткнуть своё определение перед первым определением, задав свой частный случай?
Вот я смотрю очередной раз на трейты. Первоистчник говорит:
Traits do not specify any state variables, and the methods provided by traits never directly access state variables.
Далее смотрим первую попавшуюся статью по PHP и видим:
trait Id
{
protected $id;
public function getId()
{
return $this->id;
}
}
Т.е., в PHP трейты - это не трейты, я верно понял?
И теперь вот что я хотел узнать - как соотносятся по производительности трейты с одиночным наследованием реализации. Тут я слегка упираюсь в то, что я не понимаю, как реализованы вирт. ф-ии в С++ при множественном наследовании. Как я понял, если класс Child наследует от Parent1 и Parent2, и мы хотим вызвать виртуальный метод Parent1::Method, то мы должны где-то найти указатель на этот метод. Метод ищется в VMT и Child содержит 2 VMT, для каждого из Parent.
И получается, чтобы найти этот VMT, нам нужно сначала вызвать некую ф-ю VMTOffsetOfParent1(Child). Эта функция может вызываться для всех потомков Parent1, и может принимать на вход только какое-то число, идентификатор класса, а возвращать она должна указатель. Такое отображение можно реализовать только с помощью хеш-таблицы, b-дерева или иного объекта с логарифмическим временем доступа по отношению к количеству потомков Parent1.
По сравнению с этим, при одиночном наследовании вызов вирт.метода осуществляется за линейное время.
Если Parent1 и Parent2 становятся трейтами, то опять же нам нужно вызвать функцию GetParent(Child), которая опять же требует хеш-таблицы для своей реализации, со временем доступа, логарифмическим по отношению к количеству классов, воплощающих этот трейт.
Вывод отсюда такой: одиночное наследование реализации с таблицей виртуальных методов даёт существенный выигрыш в производительности по сравнению с множественным наследованием и трейтами. Мы можем это по всячески оптимизировать, кешируя найденные трейты или VMT, но это не отменяет исходной разницы.
Наверное, я зря сюда приплёл вирт. ф-ии, поскольку затратная операция здесь - скорее dynamic_cast. Вот нашёл статейку, как подобрать хеш-функцию, чтобы не было конфликтов между классами.
Верно я мыслю или нет? В свете этого, верно ли, с точки зрения производительности, решение отказаться от наследования реализации, принятое в Rust и Golang?
А зачем мне это нужно: нужно быстро придумать, как реализовать ООП в Яре. Понятно, что нужно включить минимум для начала (потому что версия только 0.4). Но любой минимум потом оказывается более, чем минимальным, и включив что-то в язык, потом уже не избавишься. Поэтому тэг «Яр» здесь должен стоять, уж извините. Он особенно хорош тем, что те, кому я надоел, ставят этот тег в список игнорируемых.
Гуглил «декларация pure», и вот нашёл
Хех, тогда не было ещё Rust, и то, что сейчас в Rust, мне цитировали из Cyclone. Не было golang, julia. clang находился в зачаточном состоянии.
Что ж, теперь у меня есть и драфт описания, и прототип компилятора, и IDE. Вообще, наверное, жаль, что я не занялся этим вопросом своевременно, с каждым годом становится всё больше разных языков, и я тоже становлюсь всё старее, тупее и ленивее. Но ничего, есть ещё порох в пороховницах и Бог с неба тоже помогает немного :)
Но надо сказать, что пункты 1,3,6 и 8 выпали. Некоторые просто пока ждут своей очереди, а на некоторые нет сил.
Перемещено tailgunner из development
Мы с Монком начали портировать portable C compiler на Common Lisp. Получится тот же самый компилятор, но написанный на лиспе. Есть желающие подобровольничать? Репозиторий здесь
Вот смотрю Julia
Julia:
julia> Int8[[1 2] [3 4]]
1×4 Array{Int8,2}:
1 2 3 4
Смотрю Dylan: вроде есть что-то похожее на лисповый reader.
Смотрю Io: вроде есть что-то http://iolanguage.org/reference/index.html
Io> Object clone do(x:=1) serialized
==> Object clone do(
x := 1
)
Однако неясно, есть ли что-то подобное *print-readably* Соответственно, вопрос всем: где оно есть, где лично вы им пользовались?
Вопрос по дизайну языка. В CL есть destructuring-bind, но он что-то слабоват. Либо ты попал в один шаблон, либо ошибка - никакого destructuring-case нет. Кроме того, квазицитаты, которые тут просятся, использовать нельзя. По сути задействован синтаксис из определения функции, т.е. можно обязательные, необязательные, параметры ключи и сопоставление головы и хвоста списка из консов.
Когда пытаешься использовать pattern matching, сразу становится ясно, что этого мало. Нужно:
1. Нужна возможность сопоставления с несколькими шаблонами, как в case.
2. В шаблоне не всё является параметром, иногда нужно, чтобы была возможность задать фиксированные ключевые слова, которые там должны быть, но нам не нужно их видеть среди переменных.
3. Нужно иногда проверять тип значения, к-рое мы сопоставляем.
4. Иногда нужно использовать разные предикаты для сопоставления. Т.е. если мы ищем шаблон со строкой «abc», то иногда нам нужно искать без учёта регистра.
5. Если в языке есть квазицитаты, должна быть возможность строить шаблон из них, где подстановочные места будут переменными.
Я попробовал пару библиотек pattern-matching для CL, но в итоге как-то стал без него обходиться (почему-то это не сильно меня опечалило).
Тем не менее, ищутся люди, интенсивно применяющие pattern matching, и от таких людей я хотел бы узнать: язык на котором они это делают, степень вашего удовлетворения технологией и ссылка на описание технологии.
Вот смотрите. Есть такая вещь, как data breakpoint. Позволяющая отловить момент, когда какой-то урод испортил мои красивые данные в памяти, и поставить брекпойнт, который сработает в этот момент и укажет на урода.
CL, конечно же, всем прекрасен. Но для Си такая технология есть, а для CL её нет. Во всяком случае, её нет в Lispworks, SBCL и CCL. Отсутствие этой технологии является большим упущением в конкурентной борьбе, потому что эта возможность нужна (и не нужно это оспаривать).
Так вот, я сегодня посвятил большую часть дня изучению вопроса о том, что можно сделать, и у меня получился
Есть добровольцы доделать? Нужно вот что:
1. Отлавливать движение объекта при сборке мусора и переставлять брекпойнт, в чём отчасти поможет *after-gc-hooks*
2. Отключать брекпойнт на время сборки мусора.
Считайте пп 1-2 головоломкой - я думаю, что она имеет решение.
3. Другие места, а не только aref для строки
Есть много книжек, где излагаются азы программирования: структуры данных, понятие переменной, основы какого-нибудь языка и т.п.
Есть ли хоть одна (на родном языке), где излагается, как собственно, устроено ремесло программиста? Меня интересует:
Я быстренько глянул. На Си давно не писал, там вроде нельзя. В Лиспе можно, в Яве можно. В Паскале (Дельфи) вроде нельзя. В tcl можно.
Понятно, что для очень многих синтаксисов (может быть, и для Си тоже) технически легко разрешить обращаться к функциям, определённым ниже по тексту. Но я вижу одно мощное «за» запрет такого обращения - проще сделать хорошую поддержку IDE. Обычно в процессе редактирования текст до положения курсора - корректный, а ниже - сломанный. И, допустим, мы хотим в лексически корректном тексте выделить цветом ошибочные обращения к функциям. Если мы обязаны декларировать «forward reference», с этим нет проблем. Если не обязаны, то как только мы сломали текст в текущей позиции курсора, все функции, определённые ниже, строго говоря, исчезли и их больше нет. Поэтому мы не можем ничего проверить, пока текст снова всего файла снова не станет правильным. И так оно будет мелькать от каждой буквы. Дальше мы начнём кешировать, выдумывать таймауты и т.п. Но это всё как-то гнилостно.
Для собственно разработки мне кажется менее удобным требовать определения заранее. Красивая мода начинать с функции main и дальше вниз её детализировать. И не нужно повтора текста. Можно просто писать код и не отвлекаться на декларирование.
Приведите, пожалуйста, свои «за» и «против» необходимости декларировать ф-ии, к-рые будут использованы до места определения.
Насколько вам досаждает необходимость декларировать функции заранее в тех языках, где это необходимо. Я пишу почти всё время только на лиспе и уже не могу здраво оценить.
У меня складывается ощущение, что нет. Я прав?
Допустим, те, кто в настоящее время продолжает коммитить в open-source проекты. Или пилит что-то своё открытое/закрытое?
Есть "http://ystok.ru/", они в 16-м году выпустили версию своей софтины. Есть Стас Букарёв, я думаю, что он работает где-нибудь в гугле за зарплату, хотя кто знает?
Есть мы, конечно.
А ещё кто-нибудь есть?
Мне кажется, тема совсем обезлюдела.
Отзовитесь, ау!
Мы предприняли титанические усилия и реализовали интерпретатор Common Lisp (ну, почти всего), способный в любой момент приостановить своё выполнение и вернуть состояние. Состояние можно скопировать и потом перезапустить несколько раз. При этом мы умеем что-то делать и с биндингами специальных переменных. Чтобы копировать состояния эффективно, мы начали делать «версионное состояние», которое копируется более дёшево, чем просто глубокая копия графа объектов. Его, правда, пока не используем, но планируем.
Ничего, что вся эта конструкция тормозная и привязана к SBCL. На этой основе реализована раскраска Яра (пока старой версии, но не суть).
Мы напускаем наш обычный парсер, который входит в транслятор, на текст в файле. Состояние парсера запоминаем в начале каждой строки, чтобы сэкономить усилия и не парсить файл целиком с начала до конца на каждое нажатие кнопки.
Смысл всех наворотов ровно в том, чтобы иметь один общий парсер, пригодный и для компиляции, и для среды.
Но на этом страдания не закончились. Оказывается (кто бы мог подумать?), современная среда должна ещё подсказывать, чем можно продолжить текст. И оказалось что это имеет прямое отношение к грамматике языка и к информации, которую накапливает парсер.
И наш рекурсивно-спускающийся парсер не подходит для этого, потому что как кажется, подсказки можно построить (насколько я понимаю) только на основе формального описания грамматики.
Посоветуйте, какой код посмотреть, что почитать (не занудное и простое). Что взять в качестве примера парсера, который может подсказать, что сейчас ожидается. Или может быть есть идеи, как можно рекурсивно-спускающийся парсер приспособить для этого.
При этом понятно, что список ожидаемого, вообще говоря, строится динамически. Например (для лиспа), если написали (defsystem :foo (, то дальше нужно откуда-то взять список всевозможных кляуз для defsystem и предложить именно их. Это не входит в грамматику языка, а входит в метаданные. Т.е. статически сгенерировать сам список продолжений невозможно.
Пишите не ваш любимый язык, а именно ответьте на вопрос. Например, мне нравятся лисп и паскаль, но мне кажется, что текст на Си визуально наиболее красив - очень уж красивы эти фигурные скобочки.
Мнение анонимусов не учитывается.
Перемещено tailgunner из development
Упёрся. Есть такая простая вещь, как синтаксис.
Вот примеры:
ключ используется сам по себе, без значения
ls -l *.c
в лиспе ключ почти всегда используется в паре со значением
(make-foo :a 1 :b 2)
<img src="siski.png" alt="UML-диаграмма">
Но ведь есть и «синтаксис»
for i in a do
И сталкиваемся со следующими противоречиями: Если мы помечаем имя, то запись становится длиннее. Если мы не помечаем имя, то возможно возникновение неоднозначностей.
При этом в реальной жизни используется то одно правило, то другое. Не за что зацепиться, чтобы создать какие-то универсальные правила.
В языках типа С всё понятно - синтаксис там маленький и фиксированный. Все ключевые слова зарезервированы и не могут быть перепутаны с идентификаторами.
В языках с гомоиконностью, или просто в расширяемых языках так не получается. Сегодня я завёл переменную finally, а завтра в языке появилось ключевое слово finally и вот мы приехали.
В лиспе традиционно используются кейворды, например
(defsystem
:serial t
:description "Some utilities by Budden, mostly public domain"
:depends-on
(:alexandria :cl-fad :split-sequence :cl-utilities :named-readtables
:cl-ppcre
:iterate-keywords :swank :decorate-function :closer-mop)
)
Но с другой стороны, а зачем нам столько двоеточий? Если отвлечься от лисповой особенности, состоящей в том, что кейворды видны из любого пакета, ведь можно и так написать:
(defsystem
serial t
description "Some utilities by Budden, mostly public domain"
depends-on
(alexandria cl-fad split-sequence cl-utilities named-readtables
cl-ppcre
iterate-keywords swank decorate-function closer-mop)
)
Пока что моя идея состоит в том, что необязательные ключи будут начинаться с тире, как в командной строке. Обязательные будут писаться просто как слова, но синтаксис будет понимать, ожидается ли сейчас ключевое слово или данные, и так мы сможем устроить, чтобы у нас одно слово могло служить и элементом синтаксиса, и идентификатором.
Что для литералов структур (т.е. для записей вида «имя=значение, имя=значение» я налагаю требование, чтобы на каждой строке располагался или один элемент (имя или длинное значение) или целое число пар:
объект хрень
имя1
очень-длинное-значение-1
имя2 значение2
имя3 значение3 имя4 // здесь нас подстрахует парсер
имя5 значение 5 // несмотря на эту вторую ошибку
кно
Вот я читаю Википедию: алгебраический тип данных - это сумма произведений типов. ГДе произведением почему-то называется рекорд из таких типов.
Ну так и что? В С объявляем юнион из структур с тегом. В лиспе - несколько структур и or.
Конструкторы и сопоставление с образцом - это уже лирика (утилиты, так скажем). Верно я понимаю определение АТД или нет?
| ← назад | следующие → |