Как стать автором
Обновить
13
0

Software Developer

Отправить сообщение
«нафига программисту нужен системный анализ?»

Сильно! Программист — один из первых, кому нужен системный анализ.
Другое дело, что побочным эффектом внедрения agile-технологий явилось то, что под программистом теперь понимается не разработчик, а кодер (с соответствующим результатом на выходе).
Недавно я тоже разместил статью про булевы типы (но в C#), поэтому, хотя тут обсуждение и давнее, хотелось быт поднять тему.

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

1. Нативный булевский тип в C++ — это bool. Всегда используйте его с своих проектах.
Если пишите на чистом C, не поддерживающим bool, используйте в качество булева типа обычный int.
Считаю большой ошибкой использовать в своей вычислительной логике вместо стандартных типов языка типы, определенные как синонимы других типов в заголовочных файлах Windows SDK: BOOL, BOOLEAN, DWORD и т.д.
Если ваша программа может быть открыта как COM-объект, то стандартных типов данных в этом случае тоже хватит.

2. Что касается BOOL и BOOLEAN в WinAPI, то «правильный» тип — BOOL (C-Style: 32-битное целое, 0 — False, не-0 — True).
А тип BOOLEAN это Pascal-style, оставшийся в WinAPI в функциях, разработанных, когда в ранних версиях Windows API разрабатывался на паскале (1 байт, 0 — False, 1 — True).
Какой тип использовать в этом случае — определяется декларацией вызываемой функции WinAPI.
Если вы как-то в дальнейшей логике используете булевы значения, возвращенные API, то такие значение лучше сразу перевести в значения стандартного типа bool.
И, да в коде на C++ ошибки может и не быть, но в C# через P/Invoke случай нужно будет корректно обработать.
Спасибо за полезные замечания, да, начал в другого конца, про внутренности типов, а не про случаи использования. Про конкретные кейсы на C++ будет позже продолжение.
Однако, полагаю, что и при программировании на чистом C# будет полезным помнить об устройстве типов.
Верно, о них.
Я предполагал, что именно поведение отладчика сбило вас с толку.
Почему так с отладчиком происходит, понятно.
Именно поэтому поддержку в C# фильтров исключений можно только приветствовать.
Очень странно. Здесь пишут:
A throw statement can be used in a catch block to re-throw the exception that the catch block caught. In this case, the throw statement does not take an exception operand.

Если не ошибаюсь, у Рихтера было написано другое, что исключение перегенерируется так, как будто не перехватывалось.
Или, как и в некоторых других моментах, он писал о конкретной реализации, чего спецификация не гарантирует?

В любом случае, появление фильтров исключений радует, т.к. в этом случае фильтрация будет происходить средствами CLR, в то время как если мы фильтруем исключение в catch кодом, то в общем случае этот код может и не сработать, если исключение «фатальное».
Разве простой throw стирает stack trace?
throw и throw чем отличаются?
Ничем. Но вы, наверное, хотели сказать что-то другое?)

Да, другое)
throw и throw ex чем отличаются?
где ex — перехваченное исключение.
Разве?
throw и throw чем отличаются?
А еще можно в innerException поместить исходное исключение со всем стек-трейсом.
Да, это я имел ввиду — нельзя завести такое поля. Точнее выражаясь, технически завести-то можно, а логически нет.

Можно пойти дальше и отменить private секции…
Да вроде в ту ветку…

Отсюда, статическое поле «среднее по слонам» в классе Слон не должно быть, так как не является свойством экземпляра класса (среднее по слонам логически не может быть свойством объекта слон).

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

Статическое поле — это поле, назначение которого заключается в обеспечении наличия единого значения для всех экземпляров класса.

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

Таким образом, в классе ООП не нужны статические поля, а значит, если мы хотим непротиворечивой модели, то их не должно быть, т.е. компилятор их не должен допускать
Единственное исключение, на мой взгляд, я уже писал — полагаю, допустимы readonly & immutable поля (а также константы), т.к. с помощью них можно задать дополнительные характеристики типа данных (не экземпляра и не «стада экземпляров»).
Это не метасущность! У нее есть свои собственные атрибуты, собственная идентичность.
С точки зрения теории множеств — да.
С точки зрения ООП и E-R моделирования — формально и вне контекста обсуждаемой статьи — тоже да.

Я уже писал, почему в контексте «моделируем сущность средствами ООП и реляционной модели непротиворечивым образом» мы получаем конструкцию, которую можно назвать (мета)сущностью.
Хотите, берите в кавычки: создаем сущность с помощью паттерна «метасущность».

Однако, это вопрос терминов, которые неизбежно будут возникать при разработке новой парадигмы.
По более важным вопросам: достаточно сложной реализации в текущей парадигме непротиворечивой модели (мета)сущности и самой возможности реализации противоречивой модели (через один ООП-класс и статики), я уже высказался.

Слоны и стадо слонов — это две разные вещи.
У нас есть три сущности: «Слон», «Список слонов» (точнее, множество слонов — Set) и «Стадо слонов».
По вашему, какую роль выполняет сущность «Слоны»?
Очевидно, дискуссия подходит к логическому концу, т.к. очевидно, что мы говорим об один и тех же вещах, но с разных сторон:

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

Об этом я говорил с самого начала: необходимость строить такую (мета)сущность считаю недостатком парадигм ООП и E-R.
Слишком большой соблазн прямо в классе «Слон» начать плодить статик-поля, относящиеся к классу «Слоны» («Стадо слонов»). Со всеми вытекающими — об этом мы тоже говорили.

List(T) нельзя использовать в качестве множества, потому что он позволяет многократное включение одного и того же элемента.

Хотя в приведенном примере и не будет повторения (каждый раз добавляется в список новый «Слон»), то все верно:
система должна быть масштабируемой, следует ожидать в будущем добавления метода, который будет не просто добавлять нового слона в список, а добавлять уже имеющегося слона, переданного вызывающей стороной;
и здесь, чтобы не делать проверки самим на наличие экземпляра в списке (с потенциальными ошибками и уменьшением производительности), в случае использования стандартных классов, нужно использовать именно HashSet(T)
(если же проверка все равно нужна — для отслеживания повторных попыток добавления, то HashSet это позволит сделать).
Во-первых, вы только что запретили стандартную реализацию синглтона

О синглтоне я думал, но ведь вокруг него всегда столько споров, про него говорят даже «антипаттерн».

А вот неправда, у вас сейчас есть только объект и список объектов, причем для второй части паттерн встроен в любую разумную библиотеку — следовательно, поддержка уже есть.

А вот за это замечание спасибо.
Пример простой очень.

Сейчас — да, класс Elephants является всего лишь wrapper'ом (оболочкой) вокруг списка (List).
Однако, добавьте в класс Elephants поля вида:
— хозяин этого стада (множества) слонов;
— место жительства этого стада;
— да что угодно, в общем случая от предметной области зависит.

И вы получите класс, вполне подпадающей под определение «Слоны» («Стадо слонов»).
А в качестве «списка» (или «множества»?), кстати, действительно можно использовать не только List(T), но и тот же HashSet(T).

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

Изначально речь шла о недостатках моделирования предметной области с помощью ООП.
Считаю, что недостатки ООП здесь очевидны.
Вполне можно подправить и существующую парадигму (тем более не такая уж она и догматичная — посмотрите на различия Delphi, C++, C++/CLI, Java, C#, VB.NET).
В целом, конечно, речь идет о новой парадигме. От ООП мы лишь отталкиваемся.
Аргументы? Должно быть запрещено любое обращение к статикам?

Про аргументы я уже не раз писал,
а вот насчет статиков, на мой взгляд, статик-поля должны быть разрешены только в таком качестве:
readonly & immmutable.
В этом случае в таких статиках можно будет реализовать только характеристики типа данных, не данные, общие для множества,
и в этом случае, естественно, экземпляр должен иметь возможность их прочитать (как и сейчас экземпляр имеет информацию о своем типе — в C# это делается через this.GetType; да и про другие типы данных он экземпляр знает через typeof(T) — и это нормально).

Какой именно?

О котором не раз писал, и который сейчас привел — назовем его Метасущность (Объект — Список Объектов — Объекты).

(ну а вообще, второй пример в .net нативно реализуется через Set. Причем с семантикой множества.)

Вы про HashSet(T)?
Здорово, что вы знаете про это.
Однако, тут та же проблема: можно и должно.

Один из участников дискуссии, насколько я понял, сторонник первого приведенного мною примера со статиками.
Если мы с вами дадим ему задание, сильно нам поможет наличие в стандартной библиотеке класса HashSet(T)>?

Поэтому хотелось бы решения проблемы можно и должно, и реализации парадигмы множества не через класс HashSet (пусть и стандартный), а через синтаксис языка.
В моем понимании, должно быть не можно, а должно.
Т.е., в идеальной парадигме/платформе разработке первый пример не должен компилироваться, а второй должен.
И еще второй пример должен реализоваться проще, короче, «нативнее», чтобы не пришлось каждый раз плодить такой паттерн.
А теперь правильный пример (упрощенный, код реального проекта будет сложнее):

    // Класс "Слон"
    class Elephant
    {

        // Имя слона - характеристика экземпляра
        private string name;

        // Конструктор экземпляра
        public Elephant(
            string name // имя слона - входной параметр
        )
        {
            this.name = name;
        }

        // Имя слона - открытое экземплярное свойство только для чтения
        public string Name
        {
            get { return this.name; }
        }
        
        // Экземплярный метод "Бежать" - заставляет слона бежать
        public void Run(
            int speed // скорость
        )
        {
            // Здесь пишем код, который как-то обозначает, что слон бежит
        }
    }

    // Класс "Слоны" (фабрика слонов)
    class Elephants
    {
        // "Список слонов" - для упрощения его реализации используем готовый класс List<T>:
        private System.Collections.Generic.List<Elephant> elephantList;

        // Конструктор класса
        public Elephants()
        {
            this.elephantList = new List<Elephant>();
        }

        // Добавить нового слона в множество слонов
        public void AddNewElephant(
            string name // Имя слона
        )
        {
            this.elephantList.Add(new Elephant(name));
        }

        // Общее число слонов
        public int TotalElephantCount
        {
            get { return this.elephantList.Count; }
        }

        // Метод Run - завставляет бежать слона с индексом "elephantIndex" со скоростью "speed"
        public void Run(int elephantIndex, int speed)
        {
            this.elephantList[elephantIndex].Run(speed);
        }

    }
Не удержался и написал, это код на C# с комментариями.

// Класс «Слон»
class Elephant
{

// Общее число слонов — в рамках класса «Слон» эмулируем класс «Слоны»
private static int totalElephantCount;

// Имя слона — характеристика экземпляра
private string name;

// Конструктор экземпляра
public Elephant(
string name // имя слона — входной параметр
)
{
this.name = name;
}

// Имя слона — открытое экземплярное свойство только для чтения
public string Name
{
get { return this.name; }
}

// Экземплярный метод «Бежать» — заставляет слона бежать
public void Run()
{
// Здесь пишем код, который как-то обозначает, что слон бежит

// А вот тут зачем то мы обратились к данным, общим для всего множества слонов (класса «Слоны»)
// — читаем.
// Слон не должен знать эту информацию, если мы не не разрешили ему это через специальные конструкции
// Но прочитать статическое поле нам компилятор в любом случае разрешит
int count = totalElephantCount;

// А теперь отдельно взятый слон возьмет и вообще перезапишет число слонов в стаде
// (вопросы потокобезопасности вынесем пока за скобки — это схематичный пример)
totalElephantCount = 0;
}

}
И знать тоже не должен.
Если мы моделируем войсковое соединение, то при таком подходе программист может так запрограммировать бойца (любого экземпляра типа данных «боец»), что тот будет знать о всем количестве войск.
Это, очевидно, неправильно.

Идея ООП в том, что есть данные, которые вот нельзя знать (и уже тем более изменить) — абстрагирование, инкапсуляция. Иначе бы мы спокойно программировали процедурно.

Информация

В рейтинге
Не участвует
Откуда
Россия
Зарегистрирован
Активность