Входные и выходные параметры в теле функции — нормально?
Хоть сфера моя и программирование ПЛК, но вопрос "общечеловеческий".
На новом месте начал смотреть тексты программ и уже робко поднял вопрос, но мне сказали - а в чём дело, всё нормально.
Задам и вам.
Есть некие функции, которые вызываются в программе, у функций есть входные, выходные (возвращаемые, входновыходные), внутренние переменные... Ну вроде как и в обычном программировании.
Так вот, я всегда считал, что функция должна работать только с теми переменными, что она получила и выдавать значения в те, что прописаны вовне.
Тут же вижу, что раз в тексте функции идёт обращение сразу напрямую к глобальным переменным и во мне всё протестует.
Кто прав, вообще это где-то написано, что такой стиль плохой?
"функция должна" - ну строго говоря функция ничего никому не должна, функция это просто инструмент который пишет программист. Если вам нравится ФП, то вы можете приводить функции к идеальному для ФП виду (google -> "pure functions"). Если вам не нравится ФП, то можно писать их как-то по-другому. Если в вашей среде удобней использовать глобальные переменные, то почему бы и нет,
"вообще это где-то написано, что такой стиль плохой?" - напишите в гугле "global variables are bad", найдёте миллионы ответов на свой вопрос,
Вы в вопросе пользуетесь очень расплывчатыми категориями, которые к разработке не применимы: "нормально", "кто прав", "стиль плохой". Разработка это не о том что кто-то прав или что-то хорошо или плохо, разработка это о выполнении конкретных алгоритмических задач в каких-то определенных условиях. И чаще всего разработка происходит в полном соответствии с принципом "получить максимум имея минимум", который на практике означает желание заказчика тратить как можно меньше средств на разработку и желание разработчика тратить как можно меньше нервов и времени на реализацию. Бывает конечно и по другому,
Определите критерии оценки, что для вас нормально и плохо, тогда будет проще ответить на ваш вопрос
Если в вашей среде удобней использовать глобальные переменные, то почему бы и нет
Дело не в самих переменных, в них как раз ничего плохого нет.
Может плохо выразился, но вот есть функция, которая условно при наличии двух дискретных входах ПЛК включает выход контроллера. Так я бы считал, что этот выход ПЛК должен быть привязан к выходу функции, а не устанавливаться внутри её.
Вот пример набросал:
// Вызов функции
ORGANIZATION_BLOCK "Main_1"
TITLE = "Main Program Sweep (Cycle)"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
BEGIN
"FC_Set_Q"(In1 := "In1_PLC",
In2 := "In2_PLC",
Out => "Out2_PLC"); // Верное обращение к выходу ПЛК
END_ORGANIZATION_BLOCK
// Сама функция
FUNCTION "FC_Set_Q" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
In1 : Bool;
In2 : Bool;
END_VAR
VAR_OUTPUT
Out : Bool;
END_VAR
BEGIN
IF #In1 AND #In2 THEN
#Out := TRUE; // Устанавливается выход функции, нормально
"Out1_PLC" := TRUE; // Устанавливается глобальная переменная, плохо
END_IF;
Дмитрий, ну, я вообще-то ни в зуб ногой что такое ПЛК, дискретные входы и всё такое, так что мне сложно оценить всю плюсы и минусы этого подхода в данном случае. Но опять же - если я правильно понял все в вашем коде, то это ведь всё равно рабочий способ. Наверное он и правда менее очевидный чем тот который нравится вам, но думаю если именно такой используется везде в проекте, то вряд ли целесообразно проводить рефакторинг на пустом месте. Разве что найдется локальный иисус который готов будет потратить своё время на это и оттестировать результат.
Многое что может работать, но не является правильным.
Например
"Out1_PLC" := TRUE;
"Out1_PLC" := FALSE;
будет работать, но Сименс явно пишет:
DA008 Rule: Write output parameters only once
The output variables and return values are written once per execution cycle. This
shall take place, when possible, collectively towards the end of the block.
It is not permitted to read the own output parameter or return value. Instead of that
a temporary or static variable must be used.
Justification: This makes sure, that all output values are consistent.
Дмитрий, единственно правильного нет) Там в конце подписано, что это хоть её и форсят, но всё же это рекомендация. В любом случае, я думаю всё это лучше донести до вашей команды, потому что в ответ на любую вашу реплику я могу написать "это всё зависит от конкретных требований", а ваша команда вам сможет рассказать какие именно у вас там требования
Повторю ещё раз, может в комментарии не все смотрят:
spoiler
Может плохо выразился, но вот есть функция, которая условно при наличии двух дискретных входах ПЛК включает выход контроллера. Так я бы считал, что этот выход ПЛК должен быть привязан к выходу функции, а не устанавливаться внутри её.
Вот пример набросал:
// Вызов функции
ORGANIZATION_BLOCK "Main_1"
TITLE = "Main Program Sweep (Cycle)"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
BEGIN
"FC_Set_Q"(In1 := "In1_PLC",
In2 := "In2_PLC",
Out => "Out2_PLC"); // Верное обращение к выходу ПЛК
END_ORGANIZATION_BLOCK
// Сама функция
FUNCTION "FC_Set_Q" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
In1 : Bool;
In2 : Bool;
END_VAR
VAR_OUTPUT
Out : Bool;
END_VAR
BEGIN
IF #In1 AND #In2 THEN
#Out := TRUE; // Устанавливается выход функции, нормально
"Out1_PLC" := TRUE; // Устанавливается глобальная переменная, плохо
END_IF;