Именование чистых интерфейсов
От: Videoman Россия https://hts.tv/
Дата: 04.05.23 06:44
Оценка: :)
На всякий случай, используемая терминология:
PascalCase
cammelCase
snake_case

В свете переписывания библиотечного кода на кроссплатформу, принято решения использовать snake_case, как у стандартной библиотеки С++. С этим проблем нет. На 99,9% код использует шаблоны и статический полиморфизм. От сюда duck typing и никаких приседаний с именованием не требуется. Но в некоторых местах всё же необходима динамический полиморфизм и там присутствуют интерфейсы типа IBase и т.д.
Хотел коллег спросить, кто как именует чистые интерфейсные классы, в случае если везде используется snake_case ?

Какие вижу варианты:
// именование интерфейсов
struct ibase;  // [1]
struct i_base; // [2]

// именование файлов
ibase.h        // [1]
i_base.h       // [2]

Первый случай — не очевидно, что это файл интерфейса или класс интерфейса.
Второй случай — не привычно.

Еще есть какие-нибудь варианты?
Отредактировано 04.05.2023 7:00 Videoman . Предыдущая версия .
Re: Именование чистых интерфейсов
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 04.05.23 06:57
Оценка: 1 (1) +3
Здравствуйте, Videoman, Вы писали:

По сути вопроса не подскажу, так как всегда используется другая нотация. Просто по мелочи попридираюсь

V>На всякий случай, используемая терминология:
V>sname_case
V>


Я так понимаю, имелся в виду snake_case, а то у тебя везде по тексту какой-то непонятный зверь sname_case

V>В свете переписывания библиотечного кода на кроссплатформу, принято решения использовать sname_case, как у стандартной библиотеки С++. С этим проблем нет. На 99,9% код использует шаблоны и статический полиморфизм. От сюда duck typing и никаких приседаний с именованием не требуется. Но в некоторых местах всё же необходима динамический полиморфизм и там присутствуют интерфейсы типа IBase и т.д.

V>Хотел коллег спросить, кто как именует чистые интерфейсные классы, в случае если везде используется sname_case ?

Не использую snake_case, вернее, ограниченно использую в тех частях, которые типа косят под стандартную библиотеку. В остальном коде — PascalCase, функции и мемберы — camelCase. Позволяет визуально разделять C++ сущности, свои сущности, и третьесторонние сущности


V>Первый случай — не очевидно, что это файл интерфейса или класс интерфейса.

V>Второй случай — не привычно.

Ничего, привыкнешь


V>Еще есть какие-нибудь варианты?


IPascalCase

Не вижу проблемы в миксе форматирования. Интерфейсы — всегда PascalCase с префиксом I, реализации — snake_case, например
Маньяк Робокряк колесит по городу
Re: Именование чистых интерфейсов
От: so5team https://stiffstream.com
Дата: 04.05.23 07:20
Оценка: 2 (1) +2
Здравствуйте, Videoman, Вы писали:

V>Хотел коллег спросить, кто как именует чистые интерфейсные классы, в случае если везде используется snake_case ?


Иногда бывает необходимость выделить корень какой-то иерархии классов и тогда хочется, чтобы в названии было что-то, что бы говорило, что это уже корень, отсюда все и растет. В таких случаях название начинается с abstract_, вроде abstract_message_mbox, abstract_message_sink, abstract_connection_pool.

Иногда используется суффикс _iface, вроде notificator_iface, controller_iface, consumer_iface. Правильнее, наверное, было бы использовать _interface, но слишком уж длинные названия получаются. При этом _iface не обязательно означает абстрактный класс, иногда это вполне себе обычный класс, просто дающий какой-то другой способ доступа к объекту. Что-то вроде:
// Публично-доступная часть.
namespace impl {
  class private_consumer_iface;
}

class consumer {
  friend class impl::private_consumer_iface;
  ...
public:
  void a();
  void b();
  ...
};

// Приватная часть, детали реализации.
// Скорее всего, другая единица трансляции.
namespace impl {
  class private_consumer_iface {
  public:
    void c(consumer & target);
    void d(consumer & target);
    ...
  };
}


Но вообще жизненный опыт показывает, что в каком-то специальном именовании абстрактных классов смысла нет. Т.к. вначале кажется что abstract_ или _iface в названии как-то помогают, а через N лет оказывается, что то, что было чистым _iface со временем обросло и какими-то невиртуальными вспомогательными методами. А какой-нибудь abstract_ раньше был самым корнем иерархии, но со временем он сам стал производен от каких-то дополнительных классов.
Re[2]: Именование чистых интерфейсов
От: night beast СССР  
Дата: 04.05.23 08:28
Оценка: -1
Здравствуйте, so5team, Вы писали:

S>Но вообще жизненный опыт показывает, что в каком-то специальном именовании абстрактных классов смысла нет. Т.к. вначале кажется что abstract_ или _iface в названии как-то помогают, а через N лет оказывается, что то, что было чистым _iface со временем обросло и какими-то невиртуальными вспомогательными методами. А какой-нибудь abstract_ раньше был самым корнем иерархии, но со временем он сам стал производен от каких-то дополнительных классов.


интерфейсы желательно наследовать виртуально, поэтому такой префикс все-же нужен.
Re[3]: Именование чистых интерфейсов
От: so5team https://stiffstream.com
Дата: 04.05.23 08:46
Оценка: +1
Здравствуйте, night beast, Вы писали:

NB>интерфейсы желательно наследовать виртуально


Никогда так не делал, и даже сходу не припомню случая, когда это было бы нужно.

Но, наверное, если без сурового множественного наследования никуда, то такое правило может иметь право на жизнь.
Re[4]: Именование чистых интерфейсов
От: night beast СССР  
Дата: 04.05.23 08:51
Оценка:
Здравствуйте, so5team, Вы писали:

NB>>интерфейсы желательно наследовать виртуально


S>Никогда так не делал, и даже сходу не припомню случая, когда это было бы нужно.

S>Но, наверное, если без сурового множественного наследования никуда, то такое правило может иметь право на жизнь.

проектирование на интерфейсах как раз предполагает суровое множественное наследование.
а поскольку у интерфейсов часто бывает общая база, вот и выходит что без него никуда.
Re[5]: Именование чистых интерфейсов
От: so5team https://stiffstream.com
Дата: 04.05.23 08:53
Оценка:
Здравствуйте, night beast, Вы писали:

NB>а поскольку у интерфейсов часто бывает общая база


Вот с такими вещами практически не сталкивался. Разве что по молодости и сейчас уже не вспомню.
Re[6]: Именование чистых интерфейсов
От: night beast СССР  
Дата: 04.05.23 08:59
Оценка:
Здравствуйте, so5team, Вы писали:

NB>>а поскольку у интерфейсов часто бывает общая база


S>Вот с такими вещами практически не сталкивался. Разве что по молодости и сейчас уже не вспомню.


например тот же IRefCountedBase -- типа у нас все объекты с подсчетом ссылок, чтобы можно было свободно использовать ref_ptr<ISome>.
еще какие-нибудь общие вещи может захотеться по типу комовского IUnknown.
Re[7]: Именование чистых интерфейсов
От: so5team https://stiffstream.com
Дата: 04.05.23 09:03
Оценка:
Здравствуйте, night beast, Вы писали:

S>>Вот с такими вещами практически не сталкивался. Разве что по молодости и сейчас уже не вспомню.


NB>например тот же IRefCountedBase -- типа у нас все объекты с подсчетом ссылок, чтобы можно было свободно использовать ref_ptr<ISome>.


Сценарий понятен, но для моей практики очень уж экзотичен.
Re: Именование чистых интерфейсов
От: fk0 Россия https://fk0.name
Дата: 04.05.23 09:35
Оценка:
Здравствуйте, Videoman, Вы писали:


V>В свете переписывания библиотечного кода на кроссплатформу, принято решения использовать snake_case,


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

На мой взгляд для первого (типов) можно использовать CamelCase и snake_case для второго (функций, объектов).
И camelCase для объектов и CamelCase для типов. Смысл в том, что удобно видеть где тип, а где объект/функция.

V>Еще есть какие-нибудь варианты?


Оставить CamelCase для типов, не заниматься идиотскими переименовываниями и не сношать мозг.
Re[3]: Именование чистых интерфейсов
От: Videoman Россия https://hts.tv/
Дата: 04.05.23 12:54
Оценка:
Здравствуйте, night beast, Вы писали:

NB>интерфейсы желательно наследовать виртуально, поэтому такой префикс все-же нужен.

Не-не-не! Я ни за что не агитирую, каждый пусть делает как хочет, но в свое время я наелся с виртуальным наследование — во !!! У меня правило-ограничение, никогда не наследовать множественно реализацию. Только абстрактные интерфейсы, без реализации, и только агрегирование. Типа как в COM, где за 10 лет никогда не использовал никакого виртуального наследования и не жаловался.
Re[4]: Именование чистых интерфейсов
От: night beast СССР  
Дата: 04.05.23 13:02
Оценка:
Здравствуйте, Videoman, Вы писали:

NB>>интерфейсы желательно наследовать виртуально, поэтому такой префикс все-же нужен.

V>Не-не-не! Я ни за что не агитирую, каждый пусть делает как хочет, но в свое время я наелся с виртуальным наследование — во !!! У меня правило-ограничение, никогда не наследовать множественно реализацию. Только абстрактные интерфейсы, без реализации, и только агрегирование. Типа как в COM, где за 10 лет никогда не использовал никакого виртуального наследования и не жаловался.

так даимонд проблема не связана с тем, абстрактный интерфейс или нет.
у тебя один интерфейс наследует два других с общей базой -- вот уже и конфликт.
Re: Именование чистых интерфейсов
От: DiPaolo Россия  
Дата: 04.05.23 13:02
Оценка: 1 (1) +1
V>Еще есть какие-нибудь варианты?

Я раньше придерживался правила, что суффикс Base в названии класса означает интерфейс. Например, PersonBase, VehicleBase.

Альтернативный вариант начинать с I (IPerson, IVehicle) был еще раньше. Но тогда была популярна венгерская нотация и в целом такое было принято в COM. И в кроссплатформенном мире такое сильно неприятно, да и лично мне визуально не нравится.

В итоге я пришел к тому, что называю классы без всяких префиксов (Person, Vehicle). Т.к. само название класса само по себе должно давать понимание, что это за класс. И второе, пользователю класса должно быть пофигу, абстрактный он, или нет. В крайнем случае, он это поймет из контекста или из документации. Ну и помимо прочего, IDE давно уже с легкостью показывают и иерархию, и метки для абстракных/перегруженнных/наследуемых методов.
Патриот здравого смысла
Re: Именование чистых интерфейсов
От: Alekzander  
Дата: 04.05.23 13:19
Оценка: 1 (1)
Здравствуйте, Videoman, Вы писали:

V>Хотел коллег спросить, кто как именует чистые интерфейсные классы


По-COM'овски (IUnknown).
Re[2]: Именование чистых интерфейсов
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 04.05.23 13:27
Оценка: :)
Здравствуйте, fk0, Вы писали:

fk0> Оставить CamelCase для типов, не заниматься идиотскими переименовываниями и не сношать мозг.



Побуду ещё раз занудой, наверное, подразумевался PascalCase. А то CamelCase и camelCase вместе выглядят странно
Маньяк Робокряк колесит по городу
Re[5]: Именование чистых интерфейсов
От: B0FEE664  
Дата: 04.05.23 14:00
Оценка:
Здравствуйте, night beast, Вы писали:

NB>так даимонд проблема не связана с тем, абстрактный интерфейс или нет.

NB>у тебя один интерфейс наследует два других с общей базой -- вот уже и конфликт.
А в чём конфликт?
И каждый день — без права на ошибку...
Re[5]: Именование чистых интерфейсов
От: Videoman Россия https://hts.tv/
Дата: 04.05.23 14:07
Оценка:
Здравствуйте, night beast, Вы писали:

NB>так даимонд проблема не связана с тем, абстрактный интерфейс или нет.

NB>у тебя один интерфейс наследует два других с общей базой -- вот уже и конфликт.

А мне кажется связана. Виртуальное наследование это же про данные. Нет данных — нет виртуальной базы. Чистым интерфейсам не только виртуальное наследование не нужно, но и таблица виртуальных функций — всё хранится в классе.
Вот, пример:
#include <iostream>
#include <memory>

struct base
{
    virtual void base_method() = 0;
};

struct a_interface : base
{
    virtual void a_method() = 0;
};

struct b_interface : base
{
    virtual void b_method() = 0;
};

struct object : a_interface, b_interface 
{
    void base_method() override 
    {
        std::cout << "base_method" << std::endl;
    }

    void a_method() override 
    {
        std::cout << "a_method" << std::endl;
    }

    void b_method() override 
    {
        std::cout << "b_method" << std::endl;
    }
};

int main() 
{
    object obj;
    obj.base_method();
    obj.a_method();
    obj.b_method();
}

base_method
a_method
b_method

Какая разница через какой интерфейс вызов, если данные всё равно расшарены
Re[6]: Именование чистых интерфейсов
От: night beast СССР  
Дата: 04.05.23 14:16
Оценка:
Здравствуйте, Videoman, Вы писали:

NB>>так даимонд проблема не связана с тем, абстрактный интерфейс или нет.

NB>>у тебя один интерфейс наследует два других с общей базой -- вот уже и конфликт.

V>А мне кажется связана. Виртуальное наследование это же про данные. Нет данных — нет виртуальной базы. Чистым интерфейсам не только виртуальное наследование не нужно, но и таблица виртуальных функций — всё хранится в классе.


V>Какая разница через какой интерфейс вызов, если данные всё равно расшарены


ты не работаешь напрямую с объектами, ты работаешь с интерфейсами:
struct IBase {
  virtual ~IBase() {}
};

struct IA : IBase {
};

struct IB : IBase {
};

struct IC : IA, IB {
};


int main()
{
    IC * c = new IC();
    IBase* x = static_cast<IBase*>(c); // опаньки
}
Re[2]: Именование чистых интерфейсов
От: Videoman Россия https://hts.tv/
Дата: 04.05.23 14:19
Оценка:
Здравствуйте, DiPaolo, Вы писали:

DP>...


DP>В итоге я пришел к тому, что называю классы без всяких префиксов (Person, Vehicle). Т.к. само название класса само по себе должно давать понимание, что это за класс. И второе, пользователю класса должно быть пофигу, абстрактный он, или нет. В крайнем случае, он это поймет из контекста или из документации. Ну и помимо прочего, IDE давно уже с легкостью показывают и иерархию, и метки для абстракных/перегруженнных/наследуемых методов.


В том-то и проблема, что не хочется конфликтов и головняка как отличить Person от интерфейса с таким же названием. Хочется типа такого:
namespace i
{
  struct person;
} 

class person: public i::person
{
  // ..
};

Что бы не думать.
Re[7]: Именование чистых интерфейсов
От: Videoman Россия https://hts.tv/
Дата: 04.05.23 14:41
Оценка:
Здравствуйте, night beast, Вы писали:

NB>...


Тут да, неоднозначность получается. Тогда действительно можно указать virtual, показав, что мне всё равно что компилятор будет звать:
#include <iostream>
#include <memory>

struct base
{
    virtual void base_method() = 0;
};

struct a_interface : virtual base
{
    virtual void a_method() = 0;
};

struct b_interface : virtual base
{
    virtual void b_method() = 0;
};

struct с_interface : a_interface, b_interface
{
    virtual void c_method() = 0;
};

struct object : с_interface 
{
    void base_method() override 
    {
        std::cout << "base_method" << std::endl;
    }

    void a_method() override 
    {
        std::cout << "a_method" << std::endl;
    }

    void b_method() override 
    {
        std::cout << "b_method" << std::endl;
    }

    void c_method() override 
    {
        std::cout << "c_method" << std::endl;
    }
};

int main() 
{
    object obj;

    auto& c = static_cast<с_interface&>(obj);

    c.base_method();
    c.a_method();
    c.b_method();
    c.c_method();
}

Только не понятно, что изменится в самом классе в таком случае, кроме подавления ошибки компилятора, при обращении к такому методу. Интересно...
Re[8]: Именование чистых интерфейсов
От: night beast СССР  
Дата: 04.05.23 15:07
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Тут да, неоднозначность получается. Тогда действительно можно указать virtual, показав, что мне всё равно что компилятор будет звать:


не все равно.
будет один IBase. это усложняет работу с поиском нужного метода, появляются доп смещения.
в общем, насколько понимаю, такие вызовы дороже обходятся (но это не точно)
ну и сама компиляция усложняется. деталей не помню но при виртуальном наследовании где-то идет комбинаторный взрыв и память расходуется в больших объемах.
по крайней мере раньше что-то вроде:
template<int N>
struct IBase : virtual IBase<N-1>, virtual IBase<N-2> {
};

template<>
struct IBase<0> {
    virtual ~IBase() {}
};
template<>
struct IBase<1> : virtual IBase<0> {
};

быстро ложило компилятор.

V>Только не понятно, что изменится в самом классе в таком случае, кроме подавления ошибки компилятора, при обращении к такому методу. Интересно...


все усложняется, поэтому плохо что в плюсах нет полноценных интерфейсов.
Отредактировано 04.05.2023 15:07 night beast . Предыдущая версия .
Re[9]: Именование чистых интерфейсов
От: Videoman Россия https://hts.tv/
Дата: 04.05.23 15:49
Оценка:
Здравствуйте, night beast, Вы писали:

NB>не все равно.

NB>будет один IBase. это усложняет работу с поиском нужного метода, появляются доп смещения.
NB>...

Здравый смысл по прежнему отказывается это понимать. Откуда там смещения, если нет данных? По сути речь идет о статической структуре таблиц виртуальных функций, причем только одного объекта — object. Или вы хотите сказать, что указатель на таблицу виртуальных функций и будет являться не явными данными всех классов ? Почему компилятор это не оптимизирует, если мне по сути без разницы через что вызывать?
Re[10]: Именование чистых интерфейсов
От: night beast СССР  
Дата: 04.05.23 18:49
Оценка:
Здравствуйте, Videoman, Вы писали:

NB>>не все равно.

NB>>будет один IBase. это усложняет работу с поиском нужного метода, появляются доп смещения.
NB>>...

V>Здравый смысл по прежнему отказывается это понимать. Откуда там смещения, если нет данных? По сути речь идет о статической структуре таблиц виртуальных функций, причем только одного объекта — object. Или вы хотите сказать, что указатель на таблицу виртуальных функций и будет являться не явными данными всех классов ?


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

V> Почему компилятор это не оптимизирует, если мне по сути без разницы через что вызывать?


потому что компилятор во время компиляции не знает, какой метод будет вызван
Отредактировано 04.05.2023 18:53 night beast . Предыдущая версия .
Re[3]: Именование чистых интерфейсов
От: DiPaolo Россия  
Дата: 04.05.23 19:15
Оценка:
V>В том-то и проблема, что не хочется конфликтов и головняка как отличить Person от интерфейса с таким же названием. Хочется типа такого:

Я придерживаюсь мнения, что это должно быть понятно из названия. Более конкретно (я так понимаю вы работаете с видео):

Stream — очевидно, что это абстрактный класс. VideoStream — тоже абстрактный класс. AvcStream — конкретный класс для реализации H.264/AVC. То есть по контексту и физической сути класса должно быть понятно, что есть что. ИМХО, всякие IStream тут излишни, т.к. понятно, что stream (поток) — это абстрактный поток.
Патриот здравого смысла
Re[3]: Именование чистых интерфейсов
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 04.05.23 19:44
Оценка: +1
Здравствуйте, Videoman, Вы писали:

V>В том-то и проблема, что не хочется конфликтов и головняка как отличить Person от интерфейса с таким же названием. Хочется типа такого:

Если у тебя person это и интерфейс, и конкретный класс, занчит у тебя что-то не правильно с твоими абстракциями.
Sic luceat lux!
Re[4]: Именование чистых интерфейсов
От: Videoman Россия https://hts.tv/
Дата: 05.05.23 10:20
Оценка: +1
Здравствуйте, Kernan, Вы писали:

K>Если у тебя person это и интерфейс, и конкретный класс, значит у тебя что-то не правильно с твоими абстракциями.


Это можно знать только задним числом, разобравшись в иерархии. Я привел пример просто как иллюстрацию, что в общем виде, взглянув на такое имя без контекста, не понятно, что это, реализация или интерфейс. Мой вопрос, кто как это обозначает или не обозначает, просто для обмена опытом.
Есть еще одна специфика, у себя я практически не использую интерфейсы в чистом виде. У меня не COM в общем понимании. Обычно интерфейсы появляются там, где без динамического полиморфизма ну уж совсем не обойтись, что бы в функцию можно было подсунуть любой внешний сторонний класс при необходимости. Типа такого:
namespace media
{

class sample : public i_sample
{
// ..
};

}

У меня самого в библиотеке класс почти всегда один и по сути это default implementationи и она всегда устраивает, а интерфейс может понадобиться для внешнего кода. Поэтому называть все классы default_something, просто из-за наличия интерфейса мне бы не хотелось.
Потом, выделять интерфейс в имени это не я придумал, так много где делают, например Microsoft и Google те же. Проблема в том, что у них другой стиль именования и он мне не подходит.
Re: Именование чистых интерфейсов
От: Aquilaware  
Дата: 05.05.23 19:01
Оценка: 4 (1) +2
Здравствуйте, Videoman, Вы писали:

V>Еще есть какие-нибудь варианты?


Одна из самых понятных и универсальных нотаций, это простая С нотация основаная на snake case, в которой для обозначения типа используется суффикс _t:

clock_t
date_t
uuid_t

Подобный подход можно всретить даже в самом стандарте C и его стандартных библиотеках. Если продолжить эту идею, то для интерфейсов можно было бы использовать суффикc _i:

base_i

Второй очень понятный вариант — это классический pascal сase:

IBase

Наверное вот это и всё. Это два самых жизнеспособных варианта, только потому, что всё сразу понятно даже для абсолютно посторонних людей.
Re: Именование чистых интерфейсов
От: Skorodum Россия  
Дата: 08.06.23 07:55
Оценка:
Здравствуйте, Videoman, Вы писали:

Не вижу никаких преимуществ аббревиатуры-префикса перед полными словами: window_base или WindowBase >> IWindow. Использование нормальных слов ближе к духу современного C++.

В целом проще всего следовать какому-то хорошо определенному стилю: std/boost или Qt.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.