Здравствуйте, Сергей Губанов, Вы описали
два случая, но есть ещё третий — Delphi.
Вроде оно вполне модульное.
Здесь и ошибок не выдаётся, в отличии от BlackBox, и компилируется всё правильно, в отличии от .NET.
Естественно это достигается перекомпиляцией второго модуля при изменении важной константы в первом. Впрочем, если в первом поменять что-либо менее важное, например функцию, или чего добавить, то перекомпиляции второго модуля не будет.
Хотя, если добавить третий модуль и совпадающие имена, то тут Delphi опускается до уровня .NET и для правильной компиляции требуется -B = Build all units.
Здравствуйте, Ракот, Вы писали:
Р>Сергей Губанов, а зачем использовать константы, если, как правильно указал VladD2, есть readonly поля?
Так и я про то: константы и модульность, получается, являются взаимоисключающими понятиями. То есть надо либо запретить импорт / экспорт констант, чтобы случайно не нарваться на неприятности, либо явно проверять согласованность импорта при каждой загрузке (как, например, было сделано в первом примере который я привел).
Здравствуйте, andyJB, Вы писали:
JB>С рассуждением про то, что константы нельзя использовать в модульных языках не согласен. Могу ещё одно такое же рассуждение толкнуть: допустим мы объявили в первом модуле метод, а во втором его вызвали. Компилятору нужно знать сигнатуру метода, чтобы сгенерировать код его вызова. Теперь добавим в метод параметр и перекомпилируем первый модуль, не компилируя второй. Запустим и, кто бы мог подумать, все фатально навернется при вызове! Выходит, в модульных системах должно быть запрещено использование методов. Чем не бред? Все потому, что выводы мало связаны с посылками, из которых сделаны. То же произошло и в Вашем рассуждении про константы.
Думаю, что Вы правы.
Однако, .NET на неправильный метод ругнулся бы, чего он тогда на константу не ругается?
Здравствуйте, exp_1, Вы писали:
_>Здравствуйте, Сергей Губанов, Вы описали _>два случая, но есть ещё третий — Delphi. _>Вроде оно вполне модульное.
Нет. Дельфийские unit-ы модулями не являются. Модули — это не только единицы раздельной независимой компиляции, но еще и (динамически загружаемые/выгружаемые) единицы исполнения, а именно exe или dll файлы (это если под Windows).
.dcu-шник, т.е. то во что компилируются unit-ы единицей исполнения не является (тем более динамически загружаемой/выгружаемой).
Здравствуйте, Andrei N.Sobchuck, Вы писали:
VD>>Но, думаю я и так угадаю. Спецификации нужно читать. С целью увеличения быстродействия дотнет копирует (propagate) константы в применяемые модули. Другими словами константа — это ее значение.
ANS>А как же хвалёный JIT?
Это джит и делает. Почитай на досуге про компиляторыные оптимизации... есть такая штука constant folding.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Сергей Губанов, Вы писали:
СГ> exe или dll файлы
С ними ещё проще. Там нет "экспортирование / имортирование констант!"
Там есть функции, которые согласно Вашим требованиям иметь возможность изменять (например количество параметров) без общей переделки/перекомпиляции тоже нельзя использовать.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Однако, .NET на неправильный метод ругнулся бы, чего он тогда на константу не ругается?
О своем понимании того, что должно происходить, я уже писал. Оберон тут ближе всех к тому, что должно быть, но тоже не дотягивает до идеала. Относительно того, почему ребята из Microsoft поленились, как и ребята из Sun со static final, ответить не могу. Подозреваю, что, так как в Java такая ситуация большинство устраивала, в C# просто не стали заморачиваться.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Так и я про то: константы и модульность, получается, являются взаимоисключающими понятиями. То есть надо либо запретить импорт / экспорт констант, чтобы случайно не нарваться на неприятности, либо явно проверять согласованность импорта при каждой загрузке (как, например, было сделано в первом примере который я привел).
Для таких случаев есть тулзы типа FxCop. Если уж в нем нельзя задать такое правило то тулза проверяющая наличие в сборке публичных констант пишется минут за 10. Вводить же запрет на уровне языка\среды это через чур жестко ИМХО.
Здравствуйте, exp_1, Вы писали:
_>Здравствуйте, Сергей Губанов, Вы писали:
СГ>> exe или dll файлы
_>С ними ещё проще. Там нет "экспортирование / имортирование констант!"
Здравствуйте, Cyberax, Вы писали:
>> распечатывается "Module1.N = 10", в то время когда Module1.N = 20.
C> В нормальных системах такой проблемы не будет.
То есть .NET не нормальная система раз она печатает "Module1.N = 10", в то время когда Module1.N = 20.
В общем-то, я согласен с Вами. Мне тоже это кажется не нормальным.
Сергей Губанов wrote:
>>> распечатывается "Module1.N = 10", в то время когда Module1.N = 20. > C> В нормальных системах такой проблемы не будет. > То есть .NET /не нормальная/ система раз она печатает "Module1.N = > 10", в то время когда Module1.N = 20. > В общем-то, я согласен с Вами. Мне тоже это кажется не нормальным.
В .NET в сборке записываются версии сборок-зависимостей. Если при
изменении константы менять версию сборки — все будет нормально.
Здравствуйте, Сергей Губанов, Вы писали:
СГ>Модульная загадка про константу
СГ>Рассмотрим модульную расширяемую систему. Создадим первый модуль, в котором определим константу, и скомпилируем его. Создадим второй модуль, который импортирует первый модуль и использует определённую ранее константу. Скомпилируем второй модуль. А теперь возьмем первый модуль, изменим в нем значение константы на другое и скомпилируем его. Второй модуль перекомпилировать не будем. Запустим на выполнение старый второй модуль вместе с новым первым. Что произойдет? Что реально происходит в таких модульных расширяемых системах как Oberon и .NET я сообщу позже, а сейчас давайте подумаем что должно происходить. Идеальным было бы так, чтобы второй модуль использовал новое значение константы из первого модуля. Не так ли? Что этому мешает? Я думаю, что как минимум на это есть две причины. Во-первых, при компиляции второго модуля константа могла быть нужна компилятору, например, для определения размера переменных в том случае если бы она была использована, например, как размер (не динамического) массива. Во-вторых, используя константу вместо переменной компилятор может осуществить оптимизацию. Первая причина в отличие от второй является фатальной. Выходит, мы не можем ожидать от второго модуля использование константы из первого модуля? Но, не кажется ли Вам, что это какой-то бред? Второй модуль использует константу из первого модуля, которую использовать не может — точно бред, не так ли? Выходит в модульных расширяемых системах просто напросто должно быть запрещено экспортирование / имортирование констант! Ибо это просто невозможно физически реализовать.
Вряд ли это — проблема.
Если разработчик dll-модуля в .Net меняет значение публичной константы, то он меняет его публичный интерфейс.
А это низззя. Никогда. Это нарушение обратной совместимости.
Надо новую константу добавить, и всех делов.
А если уж хочется поменять константу, то извольте задать сборке новую версию, несовместимую (была 1.xx.x — стала 2.0.0 — major number поменялся — обратной совместимости нет) — тогда сборка по старому strong name не загрузится, и её пользователям придётся адаптироваться к ней и перекомпилироваться.
Вопрос только в том — если разработчик модуля такой лопух, и меняет значение константы, или сигнатуры метода, а strong name не меняет, и сборка у клиента цепляется нормально, а потом где-то в середине кода выкидывается исключение о несоответствии сигнатуры метода, или логика рушится из-за изменения константы, то хорошо бы от этого защититься как-то? Чтобы, например, в модуле хранились описания всех классов с сигнатурами методов, и констант — со значениями — для каждого модуля, который импортируется этим. И при загрузке модуля проверять все его зависимости, со всеми метаданными.
Но какие же это будут тормоза...
Это же надо будет именно при загрузке модуля загружать все его зависимости, и проверять их.
Чтобы не получить козью морду при динамической загрузке модуля где-то в середине важной процедуры.
На такую безопасность ценой таких тормозов вряд ли кто пойдёт.
Такое, наверное, надо отслеживать верификаторами вроде FxCop или, например, линковать экзешник со всеми его зависимыми dll-модулями в один большой экзешник, а по линковке и проверять. Тогда в слинкованном экзешнике будут все зависимости, и все они будут правильными.
Здравствуйте, Cyberax, Вы писали:
C>Происходит, рассчет контрольной суммы — это часть процесса подписывания. C>Подписанная либа получает GUID, по которому ее и находят остальные сборки.
Остальные сборки находят сборку по связке имя + версия + культура + публичный ключ.
C>Подписанную сборку изменить нельзя, так что при изменении константы C>придется ее переподписать и сгенерировать новый GUID. Ну а от этого уже C>остальные сборки пересоберутся.
Процесс пересобирания — это компайлтайм. Процесс нахождения сборок — это runtime. Процесс подписывания — это где-то по-середине. Ты уверен насчет ГУИД?
Ракот wrote:
> C>Происходит, рассчет контрольной суммы — это часть процесса > подписывания. > C>Подписанная либа получает GUID, по которому ее и находят остальные > сборки. > Остальные сборки находят сборку по связке имя + версия + культура + > публичный ключ.
Здравствуйте, Cyberax, Вы писали:
C>Ракот wrote:
>> C>Происходит, рассчет контрольной суммы — это часть процесса >> подписывания. >> C>Подписанная либа получает GUID, по которому ее и находят остальные >> сборки. >> Остальные сборки находят сборку по связке имя + версия + культура + >> публичный ключ.
C>Сильное имя — это вообще-то GUID и есть.
Now all the CLR team needed was to figure out an algorithm for generating a unique assembly name. Perhaps part of the name could be a large random number akin to a GUID—maybe even larger than 16 bytes, to gain some extra collision resistance. This would protect you against someone accidentally picking the same identifier that you happened to be using to name your assemblies. But it wouldn't protect you against a bad guy purposely trying to make a Trojan horse assembly that looked just like yours. So the CLR team made an interesting decision. Instead of simply using a large random number, it decided to use a 1024-bit RSA public key, which is a 128-byte number constructed from two very large, random prime numbers multiplied together.
Здравствуйте, GarryIV, Вы писали:
GIV>Для таких случаев есть тулзы типа FxCop. Вводить же запрет на уровне языка\среды это через чур жестко ИМХО.
Запрет — не нужен, конечно, а вот warning нужен обязательно. Ибо спецификация спецификацией, а с логикой такое поведение не дружит , а потому — засада, Сергей правильно заметил.