Каталог решений - Что за ? в коде, или Секретный оператор в 1С

Что за ? в коде, или Секретный оператор в 1С

Что за ? в коде, или Секретный оператор в 1С

В наличии

Инкремент, модуль и прочая магия, которая скрыта под символом «?»

Категория:

Описание

 

ДИСКЛЕЙМЕР

ВСЁ ОПИСАННОЕ НИЖЕ — НЕДОКУМЕНТИРОВАНОЕ ПОВЕДЕНИЕ!

ИСПОЛЬЗОВАНИЕ В РЕАЛЬНОМ КОДЕ ЗАПРЕЩЕНО!

АВТОР НЕ НЕСЁТ НИКАКОЙ ОТВЕТСТВЕННОСТИ И ВООБЩЕ БАКА!

 

Сколько же всего сложного и таинственного нас окружает. 

Черные дыры и сновидения. Темная материя и подсознание. Корпускулярно-волновой дуализм и 1С…

 

И ведь думаешь, что знаешь эту "1Ску" как свои пять пальцев, но стоит случайно копнуть глубже… И очередная багофича. Да ешё и какая!

В этой статье рассмотрим секретный оператор ?

О нём мало кто знает, хоть он и существует как минимум с версии 8.0.

 

В последнее время я публикую на своём телеграм-канале разные хитрые задачки с подвохом для программистов 1С. Какие-то беру "по памяти", а какие-то "рождаю" в результате экспериментов. Об этом скоро выйдет отдельная статья. И вот в очередном тесте адекватности платформы случайно натыкаюсь на такую конструкцию:

  А = ?;

 

Синтаксис-проверка прошла успешно. Никаких ошибок не высветилось. И, казалось бы, ошибка тогда должна произойти в момент выполнения…

 

 

Код успешно выполнился. Удивительно, но сработало! И тут меня понесло…

 

 

Как оказалось, знак ? ведёт себя крайне странно. Давайте посмотрим ещё раз прошлый пример.

  А = ?;

Мы создаём новую переменную и назначаем ей значение — ?. И в переменной находится Неопределенно. И, казалось бы, это и есть ответ на вопрос. Знак ? означает Неопределено.

Но что же тогда это: 

 

 

В данном коде сначала идёт объявление переменной "А". И в А установлено числовое значение "1". А далее идёт наше сравнение с ?. Если бы под знаком вопроса скрывалось Неопределено, то мы бы не попали внутрь условия. А по скрину видно, что попали.

Ну ладно, значит "?" есть что-то другое. Попробуем вывести его в сообщение:

 

 

Очень странная ошибка. "Переменная не определена (Сообщить)". Ну допустим. Добавим тогда такую переменную:

  Сообщить = "ТЕСТ";
  Сообщить(?); //Сообщит "ТЕСТ"

Данный код компилируется без ошибок. И при выполнении в 1С сообщает "ТЕСТ". То есть значение переменной Сообщить

Выходит, что символ ? указывает на предыдущее слово в коде. В данном случае, перед ? было слово Сообщить. И поэтому 1С изначально поругалась, что такая переменная не определена. А когда мы добавили переменную Сообщить, то всё стало на свои места.

То есть наш код для 1С выглядит так:

  Сообщить = "ТЕСТ";
  Сообщить(Сообщить);

 

А теперь вернемся к нашим предыдущим примерам и разберём что и как сработало. 

  А = 1;
  Если ? = А Тогда
      Сообщить(А);
  КонецЕсли;

В данном коде предыдущее слово перед ? — Если. Но оно является ключевым для 1С. Как "Цикл", "Процедура" и так далее. Поэтому, его оператор ? не учитывает и берет в качестве источника значения переменную А.

Скорректируем же этот код так, как его видит 1С:

  А = 1;
  Если А = А Тогда
      Сообщить(А);
  КонецЕсли;

Теперь всё логично. А = А и поэтому условие выполняется.

 

А что с нашим самым первым примером?

  А = ?;

На самом деле всё так же. Просто заменяем знак вопроса на предыдущее слово.

  А = А;

Да, такой код тоже странный, но в рамках 1С всё логично. Сначала объявляется переменная и в ней Неопределено. А затем происходит присвоение переменной значения из её самой. То есть опять же Неопределено. Можете проверить такой код — это хоть и выглядит странно, но работает. А почитать чуть подробнее можно в статье на ИТС: Предварительная инициализация локальных переменных

 

Но вернемся к нашим вопросам. И так, символ ? в коде означает обращение к предыдущему слову. Даже если это слово — название метода. Почему? Зачем? Скорее всего случайно. Какая-то лазейка в коде интерпретатора 1С. И вряд ли мы об этом узнаем. Но:

 

Использовать это в реальном коде нельзя!

Ведь мало ли когда это исправят. И неизвестно где это может аукнуться. Но раз уж мы эту багофичу нашли, то давайте уже и придумаем как её применить 😁🎉   Возможно, вы уже догадались…

 

Представляю вам инкремент на 1С!

  МояПеременная = 0;
  
  МояПеременная = ? + 1; //1
  МояПеременная = ? + 1; //2
  МояПеременная = ? * 5; //10
  МояПеременная = ? / 2; //5
  МояПеременная = ? - 6; //-1

Да, мы так долго ждали и вот он😅

А самое интересное, что такая возможность существовала как минимум ещё с версии 8.0 . Специально скачал старую платформу и проверил.

На самом деле такой код можно ещё упросить:

  МояПеременная = 0;
  
  ? = ? + 1; 
  ? = ? + 1; 
  ? = ? * 5; 
  ? = ? / 2; 
  ? = ? - 6; 

Но такой вариант становится менее надежным. Ведь всё работает до тех пор, пока перед ? находится МояПеременная. Если же вставить после этого какое-то другое "слово", то всё порушится.

 

Но вот ещё пример:

  А = 1;
  
  Структура = Новый Структура("А", 0);
  Структура.А = ? + 1;
  
  Сообщить(Структура.А); //Будет 2

Мы же помним, что знак ? берет предыдущее слово. Так вот в нашей строке кода это слово "А". Именно так — без "Структура". 

Поэтому 1С в таком коде вместо знака вопроса вставит "А"

  А = 1;
  
  Структура = Новый Структура("А", 0);
  
  Структура.А = А + 1;
  
  Сообщить(Структура.А); //Будет 2

Выходит, инкремент хоть и есть, но с особенностями 😁

 

Но зато появляется новая возможность применения:

  МояПеременная1 = 1;
  МояПеременная2 = 2;
  МояПеременная3 = 3;
  
  Структура = Новый Структура("МояПеременная1,МояПеременная2,МояПеременная3");
  Структура.МояПеременная1 = ?;   //1
  Структура.МояПеременная2 = ?;   //2
  Структура.МояПеременная3 = ?;   //3

В данном коде мы создали структуру и наполнили её объявленными ранее переменными. Тоже бывает удобно, когда нужно передать какой-то набор переменных метода в другой метод через структуру.

 

 

А вот ещё пример. Можно передать в какой-то метод или конструктор одно значение несколько раз:

  ПустаяДата = '00010101';
  Структура  = Новый Структура("Д1,Д2,Д3,Д4,Д5",ПустаяДата,?,?,?,?)

 

Передавать знак ? можно даже в условный тернарный оператор. Например, этот код приводит отрицательные числа к 0: 

  МояПеременная = -5;
  МояПеременная = ?(?>0,?,0);
  
  Сообщить(МояПеременная); //Будет 0

 

А этот приводит отрицательные числа к положительным:

  МояПеременная = -5;
  МояПеременная = ?(?<0,-?,?);
  
  Сообщить(МояПеременная); //Будет 5

 

Подобным образом можно присваивать дефолтные значения необязательным параметрам:

  Процедура МояПроцедура(ДополнительныеПараметры = Неопределено) Экспорт
  	
  	ДополнительныеПараметры = ?(? <> Неопределено, ?, Новый Структура);
  	
  КонецПроцедуры

Главное помнить, что знак ? берет именно предыдущее слово, поэтому вот так работать НЕ будет:

  ДополнительныеПараметры = ?(? = Неопределено, Новый Структура, ?);

1С поругается, что Переменная не определена (Структура). Ведь перед последним знаком ? слово Структура

 

Но что если использовать символ ? в параметрах?

Сделаем процедуру с параметром ? :

  Процедура МояПроцедура(?)
  		
  КонецПроцедуры
  
  МояПроцедура(1); //Выполнится
  МояПроцедура();  //Будет ошибка: Недостаточно фактических параметров (МояПроцедура)

 

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

Но мы можем сделать его необязательным:

  
  Процедура МояПроцедура(? = Неопределено)
  		
  КонецПроцедуры
  
  МояПроцедура(1);
  МояПроцедура();  //Теперь и здесь ОК
  
  

И параметр не обязан быть единственным. Можно делать разными способами:

  Процедура МояПроцедура(А, ?)
  	
  КонецПроцедуры
  
  Процедура МояПроцедура(А, ?, Б)
  	
  КонецПроцедуры
  
  Процедура МояПроцедура(?, А, Б)
  	
  КонецПроцедуры
  

 

А можно использовать Знач

  Процедура МояПроцедура(А, Знач ?)
  	
  КонецПроцедуры
  

 

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

В стеке вызовов он отображается:

 

 

А попробуем добавить второй параметр ?

  Процедура МояПроцедура(?, ?)
  			
  КонецПроцедуры

1С ругается так:

Формальный параметр с указанным именем уже определен (?)

Опираясь на текст ошибки, мы можем предположить, что 1С объявляет параметр с именем "?"

И когда мы пытаемся добавить ещё один такой параметр, то платформа ругается.

 

Как обратиться к параметру с именем "?" — неизвестно. Методы Вычислить() и Выполнить() не помогли. 

 

Но, возможно, это всё те вопросы, которые нам ещё предстоит разгадать. Секреты и загадки этой таинственной платформы под кодовым названием 1С…

 

 

Понравилась статья? 

Поставьте лайк плюс. Пишите свои идеи и комментарии по теме. Статья будет дополняться.

И переходите к другим публикациям от автора:

has been added to your cart:
Оформление заказа