All streams
Search
Write a publication
Pull to refresh
0
@Loferread⁠-⁠only

Software Dev .Net, BA, Solutions Architect, MCTS

Send message
Привет «грабли», которые отлично компилируются:
class TypeX
{
public void FnX()
{
return;
}
}

class TypeY
{
public void FnY()
{
return;
}
}

class Program
{
static void Main(string[] args)
{

TypeX instX = new TypeX();
instX.FnX();

((TypeY)((object)instX)).FnY();

}
}

А в результате отлично «грабли прилетают в лоб» в runtime: System.InvalidCastException: 'Unable to cast object of type 'ConsoleTest.TypeX' to type 'ConsoleTest.TypeY'.'
Не, не ладно. Вы используете указатель того же типа, что и присваемое ему значение, и вызываете метод, который есть у этого типа. Это совсем не то, что нужно в описанном сценарии.

Нет. В этом и нюанс.
Вы декларируете в runtime, то это указатель типа Х. Cреда исполения доблестно дергает функцию по адресу A, а там все что угодно. Хотя бы и функция с другой сигнатурой, приведет к не корректному заполнению стека вызова функции.
Типичные грабли цепочки приведения типов:
*typeX -> *void ->*typeY.
После дергаем *typeY->FnY() и получаем «грабли в лоб».
Проверка на усмотрение разрабочика и среды исполнения.

Зачем там какая-либо проверка, если там все типы явные?

Типовые проблемы в runtime: не корректный вычисленный адрес или размер данных, адрес функции.
Например переполнение стека, выход за границы массива, нулевой указатель.
Я что-то не думаю, что в C# можно так написать. Фиг с ним, с указателем, но вам же надо знать, что такое Off, а вы этого не сделаете без операции приведения типа.

Да ладно ?! :)
using System;

struct Point
{
public int x;
public int y;

public override string ToString() {
return "(" + x + "," + y + ")";
}
}

class Test
{
static void Main() {
Point point;
unsafe {
Point* p = &point;
p->x = 10;
p->y = 20;
Console.WriteLine(p->ToString());
}
}
}

в котором как раз операций приведения нет.

Проверка на усмотрение разрабочика и среды исполнения. Но, полагаю некоторые механизмы оптимизации должны быть. Глупо постоянно проверять неизменяемые вещи. Проще проверить на этапе компиляции и/или загрузки сборки.
Влияет ли это на латентность или пропускную способность памяти с учетом того, что все эти расчеты делаются на уровне стека и аккумулятора процессора?

По сравнению с отсутствием этих расчетов — конечно, влияет.

Да в общем-то нет. Как было X операций в N единиц времени, так и будет. Эти битовые маски расчитываются и контролируются аппаратно процессором в процессе исполнения комманд.

Например согласно "“Protection” руководства “Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A & 3B):System Programming Guide”

Процессор использует эту информаци. для детектирования программных ошибок результатом которых является попытка использования сегмента или шлюза (gate) неверным или неожиданным способом.

Следующий список дает примеры типичных операций в которых выполняется проверка типов (список не исчерпывающий):

В процессе определенных внутренних операций,
При вызове или переходе через call gate (или при прерывании или обработчике исключения через trap или interrupt gate) процессор автоматически проверяет что сегментный дескриптор указанный в gate является кодовым сегментом.
Когда операнд инструкции содержит селектор сегмента
определенным инструкциям разрешен доступ к сегментам или шлюзам (gates) только определенного типа, например:
Дальнему вызову CALL или инструкции JMP разрешен доступ к сегментному дескриптору содержащему «conforming code segment», «nonconforming code segment», call gate, task gate или TSS.

и
Program-Error Exceptions
Процессор генерирует одно или более исключений при обнаружении программных ошибок в процессе выполнении приложения, кода операционной системы или executive. Архитектуры Intel64 и IA-32 определяют vector number для каждого processor-detectable exception.
Исключения подразделяются на faults, traps и aborts.

Программно-генерируемые исключения
Инструкции INTO, INT3 и BOUND позволяют программную генерацию исключений. Эти инструкции позволяют выполнение проверки условий в местах выполнения потока инструкций. Например INT 3 вызывает генерацию breakpoint exception.

Machine-Check Exceptions
Процессоры семейств P6 family и Pentium предоставляют внутренние и внешние machine-check механизмы для проверки операций внутреннего аппаратного чипа и транзакций шины. Эти механизмы — implementation dependent (непереносимы). Когда процессор обнаруживает machinecheck
ошибку, процессор сигнализирует об ошибке с помощью machine-check exception (vector 18) и возвращает код ошибки.


Что касается «Предположим, что нам надо сказать „включить все фары“. Как это сделать в рамках исходного предложения, и чем это выгоднее стандартного ICollection? Напомню, что контекст — C#, .net.»
Ответ прост — кто-то должен будет сделать эту работу по выяснению наличия возможности «включить».
Например:
if (unit is IOnOff)
{
((IOnOff)unit).OFF();
}
else
{
throw new Exception();
}

или
*p->Off();

Или это сделает программист руками, или ОС внутреними функциями или CPU аппаратными возможостями. Просто обработка ошибок более дорогое удовольствие, чем нормальны код.
В общем проверка бесплатна, поскольку аппаратная и уже есть.

Эээ… нет же. Не бесплатна.

Транзисторы есть и с этой точки зрения да «уплочено». Влияет ли это на латентность или пропускную способность памяти с учетом того, что все эти расчеты делаются на уровне стека и аккумулятора процессора?
Срабатывает один раз, а не постоянно

На каждом вызове же.

Если на первом вызове выяснится, что не корректный адрес функции и приложение попробует вызвать эту функцию, то приложение будет «ломиться до посинения»? Или ОС просто прибьет не корректное приложение и на этом все закончится?
Да и после формирования пространства процесса (выделение и распределения памяти, загрузки кода и данных) ОС не занимается перетасовкой адресов функций «потому что скучно», это ответсвенность самого процесса, в рамках предоставленых прав «сегмент кода»/«сегмент данных».
Если, конечно не задаться целью наваять такое «забавное» приложение.
Но суть все равно не в этом, а в том, что в современных реалиях попытка вызвать несуществующий метод небесплатна: именно вследствие дополнительных проверок, защищающих систему от сбоев.

В общем проверка бесплатна, поскольку аппаратная и уже есть.
Срабатывает один раз, а не постоянно.
Скажем так — это неизбежное «константное» зло :) Скорее всего, обработка ошибок такого типа будет значительно дороже.

А какое отношение этот стандарт имеет к самописным идентификаторам?

Это в общем-то идентификаторы типов .Net.
И да, они самописны… компилятором :)

(более того, даже этот стандарт не говорит, что потребитель должен знать список всех типов, которые могут в него передать — только те ограничения, которые он накладывает на принимаемые типы)

И тут Вы правы, ибо этот же стандарт отдает реализацию на усмотрение разработчика :)


The choice of a particular verification process is thus a matter of engineering, based on the resources available to make the decision and the importance of detecting the type safety of different programming constructs.

Например:
When a class is loaded at runtime, the CLI loader imports the metadata into its own in-memory data structures, which can be browsed via the CLI Reflection services. The Reflection services should be considered as similar to a compiler; they automatically walk the inheritance hierarchy to obtain information about inherited methods and fields, they have rules about hiding by name or name-and-signature, rules about inheritance of methods and
properties, and so forth.
Это ваше «контролируется на уровне ОС» — это не проверка, по-вашему?

Это все таки не зависит от языка или среды исполнения. Одинаково будет «ловить ошибки» что на С++ что на Java или .Net

К примеру:
Overview of the Protected Mode Operation of the Intel Architecture

If we look back at the segment descriptor you will see information in the descriptor that relates to more than just its base address in memory (Figure 2 & Table 1). The additional information provided is primarily for the implementation of a protected system:
• How programs can access different types of segments,
• ensuring accesses within the limits of the segment (limit checking),
• maintaining privilege levels or who has access to a segment,
• and controlling access to privileged instructions.


Возвращаясь к С#
Т.е. потребитель должен знать список всех возможных TypeID, а поставщик — не забывать его обновлять, а если не дай бог поведение поменялось, то отследить это можно только тестами?

Следует ответ «Да должен знать всегда», поскольку стандарт говорит следующее:
Signatures are the part of a contract that can be checked and automatically enforced. Signatures are formed by adding constraints to types and other signatures. A constraint is a limitation on the use of or allowed operations on a value or location. Example constraints would be whether a location can be overwritten with a different value or whether a value can ever be changed.
All locations have signatures, as do all values.

Type safety and verification
Since types specify contracts, it is important to know whether a given implementation lives up to these contracts. An implementation that lives up to the enforceable part of the contract (the named signatures) is said
to be type-safe. An important part of the contract deals with restrictions on the visibility and accessibility of named items as well as the mapping of names to implementations and locations in memory.
Type-safe implementations only store values described by a type signature in a location that is assignment-compatible (§8.7) with the location signature of the location (see §8.6.1).
Type-safe implementations never apply an operation to a value that is not defined by the exact type of the value. Type-safe implementations only access locations that are both visible and accessible to them. In a type-safe implementation, the exact type of a value cannot change.
Verification is a mechanical process of examining an implementation and asserting that it is type-safe.
Verification is said to succeed if the process proves that an implementation is type-safe. Verification is said to fail if that process does not prove the type safety of an implementation. Verification is necessarily conservative:
it can report failure for a type-safe implementation, but it never reports success for an implementation that is not type-safe.
For example, most verification processes report implementations that do pointer-based arithmetic as failing verification, even if the implementation is, in fact, type-safe.

Вы думаете, при вызове несуществующего метода ничего не проверяется?

Я не думаю, я знаю. При не корректном указателе — будет попытка исполнения не корректной операции процессора или обращения по некорректному указателю.
Дальше ОС отловит ошибку и прибьет процесс. Насмотрелся :)
Например: исполнить код в области данных. Сейчас такие операции контролируются на уровне ОС).

Не говоря уже о том, что в C# — о котором идет речь в статье — это немножко невозможно без дополнительных прыжков?

Вопрос был другой и С# не касался.
А насчет С# есть стандарт:
New types—value types and reference types—are introduced into the CTS via type declarations expressed in metadata. In addition, metadata is a structured way to represent all information that the CLI uses to locate and load classes, lay out instances in memory, resolve method invocations, translate CIL to native code, enforce security, and set up runtime context boundaries.
Банально — экономия ресурсов, поскольку в RunTime ничего не проверяется.
Все проверяется на этапе компиляции статическими анализаторами (в лучшем случае).
Например, COM с такими спецэффектами работал, если руками править IDL не понимая всех последствий :)
Если еще древнее и нагляднее — динамическая загрузка DLL и ручной поиск указателей на функции :) В Pascal overlay механизм.
Это сейчас ресурсов дофига — и памяти и процессора, а раньше это был дефицит. Выравнивали побайтово, что бы поменьше места занимало.
В общем случае — да.
Не найдет ожидаемого в 'Run time' — сгенерится ошибка типа «NULL Reference exception» / «Application Exception» и т.д. в зависмости от архитектуры
Скажем так, в языках где есть множественного наследование, интерфейсы необязательны, хотя могут присутствовать.

В данном случае «интерфейс» можно представить как класс без единой строчки кода (одни декларации функций) и protected конструктор. Это фактически народ писал руками на С++ 90х годов :)
В данном случае интерфейс будет как «синтаксический сахар» для базового класса, который декларирует некоторый функционал.
A «owns» B = Composition: B has no meaning or purpose in the system without A
A «uses» B = Aggregation: B exists independently (conceptually) from A
Возможно, проекты Илона Маска позволят транслировать Интернет со спутника прямо в мозг.

Боюсь тогда будут устраивать ядерные взрывы в ионосфере, что бы заблокировать спутниковый интеренет Маска…
Самый тупой карандаш, заменяет самую острую память.
Могут просто не вводить IPv6. Остаться в IPv4, когда все пойдут дальше.
Лет на… надцать хватит. А там уже и смотреть по факту.
Самоизоляция и получится
Просто оставлю это здесь:
Сommunication planning and all aspects of communication with all interested parties

Communication plan: Showing how all aspects of communication will be handled and managed with all relevant areas and parties involved ...


А где грань, между " сиюминутных внутриполитических пропагандистских нужд" и «глобальных стратегических»?
Чух-чух — это не моя ответственность — а чья — ага, не знаю — шеф у нас проблема — чух-чух.

Именно. Шеф и юридическая или финансовая ответственность — акции, собрание акционеров, банкротство.
Если у вас есть голосующие акции — вы такой-же Шеф, если нет — то вы «сервис».
А мнение «сервиса» нафиг никому не нужно (если это не его работа советовать).
Не очень понятно, почему МТС и Lenovo мне должны советовать как правильно «красить облака», тем более что их совета не спрашивали.

В любом случае — абсолютно идеально описать процессы нельзя, на 99,99999 можно — но на 100 — нельзя.

Если мне не изменяет память, то книги по экономике 19 начала 20 века упоминали изменчивость окружения (клиенты, конкуренты, форс-мажор) и готовность к реакции и адаптации к этим изменениям.
Таков мир.
Это называется формализм. Это нормально работает, когда
а) процесс типовой и отлаженный.
б) при этом всё хорошо, все ключевые сотрудники на местах и доступны, нештатных ситуаций нет, нестандартных решений принимать не нужно

У кого-то в должностных обязанностях будет написано «разобраться в проблеме и сделать\доработать инструкцию для решения проблемы» и никакого «чух-чух-чух» не будет.
Просто у нас очень часто подход «если придумал не правильное решение — будем наказывать» Вот если бы ты подождал, то…
Все крепки задним умом.

Или вы предлагаете прогаммисту считать НДС при растаможке вместо главбуха (болеет), только на том основании, что он когда-то писал такой код?
Много кому лечили зубы, все «знают» как сверлить пломбировать (на себе все проверили). Давайте зубы по этому приниципу лечить? Апендицит резать?
Программист не знающий всех нюансов предметной области в медицине сам «улучшит» код, ведь аналитик то болеет…
Где граница — сюда лазить не стоит? Не зря должностые инструкции написаны. Не кровью (как техника безопастности), но, думаю, «отсидками» точно…

P.S. Где-то читал, что было правило при проведении трибунала: при рассмотрении дела обязаны были исходить только из той информации, что была доступна обвиняемомую в момент совершения действия или бездействия

Information

Rating
Does not participate
Registered
Activity