LINUX.ORG.RU

Помогите мне разупороться....

 , , , ,


0

1

В продолжении темы Аргументы за и против длинных имён функций. Я вот сидел и думал как организовывать для себя API с учётом что пользоваться буду только я один и пришёл к выводам что

  • 1- Функции должны быть маленькими и делать только что-то одно и делать это хорошо.
  • 2-Имена функций должны быть явными и исключить неоднозначности длинна именования не является важной
  • 3-Имена функций должны быть единообразными, они не должны выглядеть чужеродными внутри одного проекта
  • 4-Обработка ошибок должна быть заложена в сами функции и производится автоматически
  • 5-Если возможно избежать побочных эффектов, констант,флагов и прочего это избегается ибо пункт 1

Я решил, жёстко следовать этим правилам, по итогу у меня человеко читаемые функции которые не надо помнить ибо их имя это имя + глагол + дополнение в зависимости от контекста и всё. Да , длинно функции плодятся, но было всё здорово... пока я не пришёл к обработке клавиатуры и там у меня более 500 функций Карл! на каждую клавишу и символ, типа так

bool keyboard_event_keydown_shift();
bool keyboard_event_keyup_shift();
bool keyboard_state_key_shift();
bool keyboard_bind_key_shift(void(*callback)(bool));
bool keyboard_unbind_key_shift(void(*callback)(bool));

Блин, оно всё удобно, имена явные, можно убрать shift в аргумены сведя сотни функций к одной,но усложнится реализация,а длинна останется той же ибо shift как аргумент никуда не денется,и да если что состояние клавиши и эвенты нажал/отпустил это разное если что, я не знаю, я что-то делаю не так...

Я хочу при построении API явность, единообразность, простоту, с тем как я к этому подхожу выходидят побочки в виде очень большого API и порой очень длинных функций. Я хотел сделать всё по иному, но каждый раз прихожу к вот этому. Ну вот к примеру полностью законченная обработка мышки



#ifndef cmouse_h
#define cmouse_h
#include "cgraphics.h"
#include "cengine.h"
#include "cevent.h"

typedef struct mouse mouse;
typedef struct mouse
{
    struct{
    int    position_x;
    int    position_y;
    vec2   position;
    int    relative_x;
    int    relative_y;
    vec2   relative;
    bool   keydown_left;
    bool   keydown_right;
    bool   keydown_middle;
    bool   keyup_left;
    bool   keyup_right;
    bool   keyup_middle;
    bool   wheel_up;
    bool   wheel_down;
    bool   wheel_left;
    bool   wheel_right;
    bool   evented_key;
    bool   evented_wheel;
    bool   evented_position;
    bool   evented;
    }event;
    struct{
    int    position_x;
    int    position_y;
    vec2   position;
    bool   key_left;
    bool   key_right;
    bool   key_middle;
    bool   relative_mode;
    }state;
}mouse;

/*       ==debug==        */
mouse mouse_get();
void  mouse_print(mouse mou);

/*       ==events==        */
bool  mouse_evented();

bool mouse_evented_position();
vec2 mouse_event_position();
int  mouse_event_position_x();
int  mouse_event_position_y();

vec2 mouse_event_relative();
int  mouse_event_relative_x();
int  mouse_event_relative_y();

bool mouse_evented_key();
bool mouse_event_keydown_left();
bool mouse_event_keydown_right();
bool mouse_event_keydown_middle();
bool mouse_event_keyup_left();
bool mouse_event_keyup_right();
bool mouse_event_keyup_middle();

bool mouse_evented_wheel();
bool mouse_event_wheel_up();
bool mouse_event_wheel_down();
bool mouse_event_wheel_left();
bool mouse_event_wheel_right();
/*       ==states==        */
bool mouse_state_key_left();
bool mouse_state_key_right();
bool mouse_state_key_middle();

vec2 mouse_state_position();
int  mouse_state_position_x();
int  mouse_state_position_y();

vec2 mouse_state_relative();
bool mouse_state_relative_mode();


/*     ==setters event+state==    */
void mouse_set_position(int x, int y);
void mouse_set_position_x(int x);
void mouse_set_position_y(int y);

void mouse_set_relative_mode(bool rel);

void mouse_set_relative(int x, int y);
void mouse_set_relative_x(int x);
void mouse_set_relative_y(int y);

void mouse_set_keydown_left();
void mouse_set_keydown_right();
void mouse_set_keydown_middle();

void mouse_set_keyup_left();
void mouse_set_keyup_right();
void mouse_set_keyup_middle();

void mouse_set_wheel_up();
void mouse_set_wheel_down();
void mouse_set_wheel_left();
void mouse_set_wheel_right();

/*if you need nonconflict relative status mouse
   use this template
   --------------------------------------------
   static  int curr_x=0;
   static  int curr_y=0;
   int prev_x=0;
   int prev_y=0;
   prev_x = curr_x;
   prev_y = curr_y;
   curr_x = mouse_state_position_x();
   curr_y = mouse_state_position_y();
   int rel_x = curr_x - prev_x;
   int rel_y = curr_y - prev_y;
   ---------------------------------------------
   rel_x and rel_y it actual relative 
   value for current frame time
 */

 /*              ==binds==             */
 bool mouse_bind(void(*callback)(mouse));
 void mouse_unbind(void(*callback)(mouse));
 void mouse_bind_update(void);

 bool mouse_bind_evented(void(*callback)(bool));
 bool mouse_bind_evented_key(void(*callback)(bool));
 bool mouse_bind_evented_wheel(void(*callback)(bool));
 bool mouse_bind_evented_position(void(*callback)(bool));
 bool mouse_bind_event_position(void(*callback)(vec2));
 bool mouse_bind_event_position_x(void(*callback)(int));
 bool mouse_bind_event_position_y(void(*callback)(int));
 bool mouse_bind_event_relative(void(*callback)(vec2));
 bool mouse_bind_event_relative_x(void(*callback)(int));
 bool mouse_bind_event_relative_y(void(*callback)(int));
 bool mouse_bind_event_keydown_left(void(*callback)(bool));
 bool mouse_bind_event_keydown_right(void(*callback)(bool));
 bool mouse_bind_event_keydown_middle(void(*callback)(bool));
 bool mouse_bind_event_keyup_left(void(*callback)(bool));
 bool mouse_bind_event_keyup_right(void(*callback)(bool));
 bool mouse_bind_event_keyup_middle(void(*callback)(bool));
 bool mouse_bind_event_wheel_up(void(*callback)(bool));
 bool mouse_bind_event_wheel_down(void(*callback)(bool));
 bool mouse_bind_event_wheel_left(void(*callback)(bool));
 bool mouse_bind_event_wheel_right(void(*callback)(bool));
 bool mouse_bind_state_key_left(void(*callback)(bool));
 bool mouse_bind_state_key_right(void(*callback)(bool));
 bool mouse_bind_state_key_middle(void(*callback)(bool));
 bool mouse_bind_state_position(void(*callback)(vec2));
 bool mouse_bind_state_position_x(void(*callback)(int));
 bool mouse_bind_state_position_y(void(*callback)(int));
 /*                 ==unbinds==                       */
 void  mouse_unbind_event_position(void(*callback)(vec2));
 void  mouse_unbind_event_position_x(void(*callback)(int));
 void  mouse_unbind_event_position_y(void(*callback)(int));
 void  mouse_unbind_event_relative(void(*callback)(vec2));
 void  mouse_unbind_event_relative_x(void(*callback)(int));
 void  mouse_unbind_event_relative_y(void(*callback)(int));
 void  mouse_unbind_event_keydown_left(void(*callback)(bool));
 void  mouse_unbind_event_keydown_right(void(*callback)(bool));
 void  mouse_unbind_event_keydown_middle(void(*callback)(bool));
 void  mouse_unbind_event_keyup_left(void(*callback)(bool));
 void  mouse_unbind_event_keyup_right(void(*callback)(bool));
 void  mouse_unbind_event_keyup_middle(void(*callback)(bool));
 void  mouse_unbind_event_wheel_up(void(*callback)(bool));
 void  mouse_unbind_event_wheel_down(void(*callback)(bool));
 void  mouse_unbind_event_wheel_left(void(*callback)(bool));
 void  mouse_unbind_event_wheel_right(void(*callback)(bool));
 void  mouse_unbind_state_key_left(void(*callback)(bool));
 void  mouse_unbind_state_key_right(void(*callback)(bool));
 void  mouse_unbind_state_key_middle(void(*callback)(bool));
 void  mouse_unbind_state_position(void(*callback)(vec2));
 void  mouse_unbind_state_position_x(void(*callback)(int));
 void  mouse_unbind_state_position_y(void(*callback)(int));
 
#endif

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

Короче, я хочу просто идей,как сделать по иному, не частных случаев типа «нуууу можно заменить position на pos» или «ну можно вынести всё в аргументы и завести 100500 флагов и констант»,а хочется принципиальных изменений где сочетаются пункты которые я выше указал, то как я сделал мне очень удобно, но одновременно очень не нравится ибо оно громоздко и по итогу уродливо вот чисто визуально.

уродливо вот чисто визуально.

Мне кажется, что и использовать это уродливо. Если клавиши будут браться из конфига, то весь код с условиями и флагами для выбора нужной функции появится на стороне вызова. Так что я бы пересмотрел изначальные выводы, в частности не доводил бы

1- Функции должны быть маленькими и делать только что-то одно и делать это хорошо.

до такой терминальной стадии, когда они становятся примитивными. Это как если бы вместо cat были программы cat-first-line, cat-second-line и т.д.

xaizek ★★★★★ ()

ну можно вынести всё в аргументы и завести 100500 флагов и констант

А почему нет? Это же прямо напрашивается, пачки bool делать битовыми флагами, все эти отдельные (x, y) объединить во что-то вроде «координата», символы держать в перечислениях/int.

Ничего страшного, все так делают

vmx ★★ ()

Блин, оно всё удобно, имена явные, можно убрать shift в аргумены сведя сотни функций к одной,но усложнится реализация,а длинна останется той же ибо shift как аргумент никуда не денется,и да если что состояние клавиши и эвенты нажал/отпустил это разное если что, я не знаю, я что-то делаю не так...

А если завтра войдут в моду не 105 клавиатуры, а, например, 139 - ты под эту клаву будешь приложение переписывать? А если тебе понадобится поддерживать мультимедийные клавиши, ты все их варианты к себе в приложение запилишь?

Тебе по нажатию клавиши (с учётом модификаторов) нужно выполнять какое-то действие.

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

Заведи себе функцию, которой ты передашь кейкод, она получит указатель на действие, и, если не налл, то выполнит его.

Как обзывать и организовывать действия - на твоё усмотрение. Лучше привязки сохранять в мультимапу, чтобы по одной клавише/комбинации можно было выполнять несколько действий (если хочешь это запретить, запрещай при установке привязок. Код при вызове нескольких действий должен отрабатывать корректно).

Хардкодить обработчики для каждой клавиши - это вообще жесть.

Ivan_qrt ★★★★ ()

Я вот сидел и думал как организовывать для себя API

Сделай примеры использования твоего API v0.0.1, публикуй хоть под GPL, хоть под Apache. Продолжай развитие АПИ и примеров, с привлечением юзеров. Читай issues, думай уже предметно, как улучшить. Если проект востребован, то через соню-другую issues ты выпустишь API v1.0

Иначе, попроси лошадь, у нее голова больше, пусть думает.

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

PtiCa ★★★★★ ()

Совсем поехавший? Сделай просто битовый вектор и проверяй по маске одной (ОДНОЙ!) функцией.

там у меня более 500 функций Карл

Чё-то мало. Должно быть 105! (факториал), ибо все комбинации, а не только нажал какую-то одну клавишу.

no-such-file ★★★★★ ()
Последнее исправление: no-such-file (всего исправлений: 1)

Для меня это тоже вопрос, к 100% решению я пока не пришел, но пока выводы такие:
1. Строго говоря, имя объекта или namespace'а - это тоже часть имени функции. Так что если у тебя много функций начинающихся на keyboard_*, имеет смысл задать вопрос: а не удобней ли создать объект (сорри что лезу с плюсами в православный Си)
2. Чтобы удовлетворить оба требования «исключить неоднозначности» и «короткие имена», можно использовать сокращения. Варианты сокращения, каждый выберет под себя:

bool mouse_event_keydown_left();
bool mouse_event_keydown_l();
bool mouse_event_kd_l();
bool mouse_evt_kd_l();
bool mouse_e_kd_l();
bool m_event_kd_l();
...

Kroz ★★★★★ ()

Имена должны быть понятны тому, кто в них может сунуться. Т.е. в обычном случае всем программистам. А программисты kbd и pos вполне поймут. Но могут быть исключения - проекты со сложной предметной областью, которую в любом случае нужно знать для работы в проекте. Там можно пойти ещё дальше.
Эталон краткости из палаты мер и весов - https://github.com/PlanetAPL/j-language/tree/master/jsrc

snizovtsev ★★★ ()

можно разбить одну сущность на несколько, например для event:


struct mouse_events {
	bool (*is_keydown_left)();
};

struct mouse {
	struct mouse_events* mouse_events;
};

/*
  приватно
*/
static bool is_keydown_left()
{
	printf("is_keydown_left?\n");
	return true;
}

static struct mouse_events mouse_events = {
	.is_keydown_left = is_keydown_left
};

/*
  публично
*/
struct mouse mouse = {
	.mouse_events = &mouse_events
};

/*
  использование
*/
void mouse_events_check()
{
	struct mouse_events* me = mouse.mouse_events;

	if(me->is_keydown_left())
	{
		printf("keydown is left\n");
	}
};

zudwa ()

Лютейший говнокод. А ещё ты лишнее таскаешь. Так значительно лучше:

struct move_event {
    vec2 cur;
    vec2 prev;
    /* etc */
};

vec2 move_event_cur_pos(const move_event *ev);
float move_event_cur_pos_x(const move_event *ev);
float move_event_cur_pos_y(const move_event *ev);

vec2 move_event_prev_pos(const move_event *ev);
float move_event_prev_pos_x(const move_event *ev);
float move_event_prev_pos_y(const move_event *ev);

vec2 move_event_delta_pos(const move_event *ev);
float move_event_delta_pos_x(const move_event *ev);
float move_event_delta_pos_y(const move_event *ev);
/* etc */

dearAmomynous ()
Последнее исправление: dearAmomynous (всего исправлений: 1)

Я читал, что когда шизофреника просят нарисовать дом, он старательно рисует кирпичик. Потом ещё кирпичик. И ещё один... Что-то в этой реализации есть от такого подхода.

Diff ★★★★ ()
Ответ на: комментарий от linux-org-ru

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

anonymous ()

UDP: ну значит я шизик ну и ладно, бог с этой шизанутостью ))) Ещё раз всем спасибо, перенамудрил на уже вот это. Единтвенное что так «строковые» константы вместо целочисленных, более удобно работать с конфигами по итогу, да на strlen тактов дольше сравниваться будут значения, но нет мусора в глобальном пространстве. Не идеал, но всё же, компромисс.


#ifndef cmouse_h
#define cmouse_h
#include "cgraphics.h"
#include "cengine.h"
#include "cevent.h"

static const char * mouse_names[] =
{
    [0] = "left"  , /*for key and wheel*/
    [1] = "right" , /*for key and wheel*/
    [2] = "middle", /*for key*/
    [3] = "up"    , /*for wheel*/
    [4] = "down"  , /*for wheel*/
};
typedef struct mouse{
    int    position_x;
    int    position_y;
    vec2   position;
    bool   key_left;
    bool   key_right;
    bool   key_middle;
    bool   relative_mode;
    struct{
    int    position_x;
    int    position_y;
    vec2   position;
    int    relative_x;
    int    relative_y;
    vec2   relative;
    bool   keydown_left;
    bool   keydown_right;
    bool   keydown_middle;
    bool   keyup_left;
    bool   keyup_right;
    bool   keyup_middle;
    bool   wheel_up;
    bool   wheel_down;
    bool   wheel_left;
    bool   wheel_right;
    bool   evented_key;
    bool   evented_wheel;
    bool   evented_position;
    bool   evented;
    }event;
}mouse;

/*      == debug ==       */
mouse mouse_get();
void  mouse_print(mouse mou);

/*      == mode ==        */
bool mouse_get_relative_mode();
void mouse_set_relative_mode(bool enable);

/*       ==events==        */
bool mouse_evented();
bool mouse_evented_key();
bool mouse_evented_wheel();
bool mouse_evented_relative();
bool mouse_evented_position();

vec2 mouse_event_position();
int  mouse_event_position_x();
int  mouse_event_position_y();

vec2 mouse_event_relative();
int  mouse_event_relative_x();
int  mouse_event_relative_y();

/*left,right,middle,*/
bool mouse_event_keyup  (char * key);
bool mouse_event_keydown(char * key);
/*left,right,up,down*/
bool mouse_event_wheel(char * wheel);

/*       ==states==        */
/*left,right,middle,*/
bool mouse_get_keystate(char * key);
vec2 mouse_get_relative();
vec2 mouse_get_position();
int  mouse_get_position_x();
int  mouse_get_position_y();

/*     ==setters event+state==    */
void mouse_set_postition  (int x,int y);
void mouse_set_postition_x(int x);
void mouse_set_postition_y(int y);

void mouse_set_relative  (int x,int y);
void mouse_set_relative_x(int x);
void mouse_set_relative_y(int y);

/*up,down,left,right*/
void mouse_set_wheel(char * wheel);
/*left,right,middle*/
void mouse_set_keyup  (char * key);
void mouse_set_keydown(char * key);

/*      ==binds==       */
bool mouse_bind(void(*callback)(mouse));
void mouse_unbind(void(*callback)(mouse));
void mouse_bind_update(void);

 /*if you need nonconflict relative status mouse
   use this template
   --------------------------------------------
   static  int curr_x=0;
   static  int curr_y=0;
   int prev_x=0;
   int prev_y=0;
   prev_x = curr_x;
   prev_y = curr_y;
   curr_x = mouse_get_position_x();
   curr_y = mouse_get_position_y();
   int rel_x = curr_x - prev_x;
   int rel_y = curr_y - prev_y;
   ---------------------------------------------
   rel_x and rel_y it actual relative 
   value for current frame time
 */
#endif

linux-org-ru ()
Ответ на: комментарий от snizovtsev

думается на свете не так уж много людей, которые захотят в подобном https://github.com/PlanetAPL/j-language/blob/master/jsrc/ab.c#L155 разбираться. разрабы фактически изобрели brainfuck на с. когда приводишь довод, надо руководствоваться своей головой, а не чьими-то упоротыми отзывами.

vtVitus ★★★★★ ()
Последнее исправление: vtVitus (всего исправлений: 1)

Когда я учился в школе, информатичка рассказывала про одного парня, чуть старше нас, который писал паскалевские программы с именами переменных вроде «kolichestvovagonovstojaschihnazapasnyhputyah».

Miguel ★★★★★ ()
Ответ на: комментарий от snizovtsev

ну ты ходь по своей ссылке ходил? не знаю, каким тайным знанием надо обладать, чтобы ЭТО понимать.

С другой стороны J как-то тоже смахивает на write-only, так что может и не обфускатор )

Сам я J использовал для лабораторных, вот весь мой опыт

deadplace ()

не дочитал оп пост до конца и потому удалил свой пост (если интересно см удалённые). Итак.

1- Функции должны быть маленькими и делать только что-то одно и делать это хорошо.

Не объясняется что такое «маленькие» функции. Если у тебя есть функция sdelat_zashibis(int naskolk_zashibis); то это попадает под твой критерий?

Я бы убрал из твоего списка идей термин «маленькими» или уточнил его. Потому что ничего не мешает это твоё что-то одно сделать более общим понятием (в противовес более конкретному).

2-Имена функций должны быть явными и исключить неоднозначности длинна именования не является важной

Если можно сократить имя функции, при этом человек недалёкий от IT может понять о чём идет речь, то почему бы и нет?

3-Имена функций должны быть единообразными, они не должны выглядеть чужеродными внутри одного проекта

Вспоминается лекция какого-то челика, уже не помню какого, где он сравнивал именование строковых функций в php, это просто жестяк. Хороший пункт.

4-Обработка ошибок должна быть заложена в сами функции и производится автоматически

Это как? Ну случилась у тебя ошибка. У тебя же логика работы ПО изменяется, не?

5-Если возможно избежать побочных эффектов, констант,флагов и прочего это избегается ибо пункт 1

Ну вот ты и наплодил миллионы функций. Убери просто этот пункт и всё. Нет ничего плохого в константах. Если у тебя есть множество - то тебе нужно его выражать в виде множества а не плодить функции на каждый элемент.
За тебя даже придумали «красивый» вариант в виде enum.

reprimand ★★★★★ ()
Ответ на: комментарий от reprimand

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

Сокращения возможны, но следуя пункту единообразности и общего соглашения если я в одной части api использую полные имена + get/set для получения состояния как общие глаголы действия и event как указание контекста действия в рамках inputs куда входят мышка/клава/окно/геймпад/etc то я либо должен применять это везде либо применить сокращения ко всему, а так же указывать или не указывать глаголы,пре/постфиксы. Исключения возможны только в отдельных случаях когда следование общим правилам ну никак не ложится на новое требуемое имя для функции или её работу или напрямую искажает её смысл или вид.

Обработка ошибок отдельный пункт да тут всё так себе но обработкой ошибок должен заниматься обработчик ошибок, ошибки передаются в него из него же получаются, этот пункт скорее просто конкретно мне уместен, во время разработки всеошибки фатальны, во время нормальной работы при ошибке нельзя падать если это не низкий уровень, мы просто не будем ничего делать выкидывая ошибку тут всё зависит от контекста опять же, но выявление ошибки (например открытие файла с конфигом которого нет) должно быть внутри открывающей функции мы получим NULL в значении но это событие должно быть обработано и если возможно записано а ещё занесено в стек ошибок откуда её можно получить как последнюю типа как с extern error;

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

По поводу аргументов, да enum`мы это хорошо, но я остановился на «строковых» аргументах, на скорость влияет пренебрежительно мало, конкретно мне более удобны для комбинирования с другими функциями, вид не портит и не засоряет скоп ещё одним ворохом глобальных констант, enum`мы хороши только когда они static const в объектном отдельном файле ну собственно строковые представления в них и мапятся в реализации той же клавиатуры уже Вместо этого в api у меня уже массив char *

Короче как то так )

linux-org-ru ()
Ответ на: комментарий от anonymous

Ой давай не будем =) Я и так диву даюсь более менее адекватности треда не смотря на тему, срачка C vs C++/Rust/Go конечно весело. Но сойдёмся на том что я знаю только С и то хреново знаю, даже не так, хреново умею/могу/в состоянии использовать ::) + основная кодовая база на нём. А она не моя, это допил форка под мои нужды.

linux-org-ru ()
Последнее исправление: linux-org-ru (всего исправлений: 1)
Ответ на: комментарий от linux-org-ru

Сокращения возможны, но следуя пункту единообразности и общего соглашения если я в одной части api использую полные имена + get/set для получения состояния как общие глаголы действия и event как указание контекста действия в рамках inputs куда входят мышка/клава/окно/геймпад/etc то я либо должен применять это везде либо применить сокращения ко всему

Если правило звучит как «использовать человекопонятные сокращения, то их можно использовать», то в местах где ты используешь полные имена значит, что сократить их невозможно или нецелесообразно.
Не вижу нарушения правила. Делать из своего кода очередную многословную Java, где кода много, а дела мало такая себе преспектива.

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

В результате у тебя нет зоопарка функций, нету шокового состояния у программиста, когда от обилия функция (и документации к каждой из них) начинают разбегаться глаза. От того что кол-во аргументов у функции увеличится с 0 до 1 или 2 ничего страшного не случиится.

Главное не впадать в крайность когда этих агрументов более 5 - привет WinAPI.

К слову, когда ты ВЫНУЖДЕН передавать тучу аргументов то предлагаю вот такое элегантное решение (думаю до меня его давно изобрели):

1) Передаём структуры в качестве аргумента для функций
2) Используем designated initializer. Крутотень в том, что зачастую программисту нужно установить лишь парочку аргументов в какое-то НЕстандартное значение, остальные обычно 0 или NULL. По умолчанию designated initializer инициализирует неуказанные поля в 0.
3) Для удобства (а иногда и для экономии памяти на стеке) можем прятать все структуры-аргументы функций в union:

typedef struct {
	int field1;
	int field2;
} blabla_t;

typedef struct {
	float f1;
	int z2;
} foobar_t;

void aaaaa() {
	union {
		blabla_t blabla;
		foobar_t foobar;
	} args;
	// ...
}



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

reprimand ★★★★★ ()