Передача параметров процедур и функций. Особенности "Знач"

10.01.25

Разработка - Механизмы платформы 1С

Особенности "Знач" и разбор документации к нему.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование Бесплатно
Передача параметров процедур и функций. Особенности "Знач".:
.epf 6,42Kb
13
13 Скачать бесплатно

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

Выражаю большую благодарность моим друзьям и коллегам, негласным соавторам данной публикации, за помощь в понимании сути, обсуждениях, разбор и детализацию отдельных, наиболее сложных и неявных  особенностей поведения передачи параметров, в частности "Знач", а именно Сергею Шикуткину и Руслану Григорьеву.

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

Итак:

Пример1

4.7.4.2. Вызов без передачи управления с клиента на сервер

Если вызов происходит без передачи управления между клиентом и сервером (вызов происходит только на клиентской или только на серверной стороне), то по умолчанию параметры передаются по ссылке. При этом изменение формального параметра ведет к изменению соответствующего фактического параметра. С помощью модификатора Знач перед именем формального параметра можно указать, что параметр передается по значению. В этом случае нельзя изменить значение фактического параметра путем присвоения формальному параметру какого-либо значения.

&НаКлиенте
Процедура МояПроцедура()
    А = 100;
    ПоСсылке(А);
    // Переменная А = 40, так как в теле процедуры значение
    // параметра Параметр1 изменено на 40.
    // Изменение переменной А произошло потому, что параметр передавался по ссылке
    А = 100;
    ПоЗначению(А);
    // Переменная А = 100, несмотря на то, что в в теле процедуры
    // значение параметра Параметр1 изменено на 40.
    // Изменение переменной А не произошло, так как параметр передавался по значению
КонецПроцедуры

&НаКлиенте
Процедура ПоСсылке(Параметр1)
    Параметр1 = 40;
КонецПроцедуры

&НаКлиенте
Процедура ПоЗначению(Знач Параметр1)
    Параметр1 = 40;
КонецПроцедуры

Тут все понятно. Вопросов нет.

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

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

"Комментами по коду отметил..." "Отсюда делаем логический вывод"

&НаКлиенте
Процедура МояПроцедура()
    Массив = Новый Массив;
    Массив.Добавить(12);
    Массив.Добавить(18);
    // В массиве есть два элемента
    ПоЗначению(Массив);
    // Массив пустой, но это по прежнему массив, а не Число
КонецПроцедуры

// Параметр передается по значению
&НаКлиенте
Процедура ПоЗначению(Знач Параметр)
    // В массиве два значения
    Параметр.Очистить();
    // В массиве нет значений!
    // Меняем формальный параметр
    Параметр = 14;
    // Изменено значение только формального параметра
КонецПроцедуры

Попробуем промоделировать данную особенность, которая ни так уж и выделяется в тексте. Мы хотим изменить значение параметра в другой процедуре и не возвращать новое полученное значение в фактический параметр "Структура", поэтому с радостью используем "Знач" перед формальным параметром в процедуре "ИзменитьСтруктуру1". Помним, что у нас в данном случае "Вызов без передачи управления с клиента на сервер", т.е. либо весь код выполняется только на клиенте, либо только на сервере, а значит параметр передается по ссылке, или по значению, если указано Знач. (Это не буду разжевывать. Есть в документации выше. Читаем ее. Далее по тексту буду просто вставлять цитаты из документации):

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

&НаСервере
Процедура Тест1()
	
	Структура = Новый Структура;
	Структура.Вставить("Тест", "Привет"); // Структура.Тест = "Привет"
	
	// После вызова и выполнения процедуры
	// Структура.Тест = "Пока"
	ИзменитьСтруктуру1(Структура);
	
	Результат = Структура.Тест; // Структура.Тест = "Пока"
	Сообщить(Результат);
	
КонецПроцедуры

&НаСервере
Процедура ИзменитьСтруктуру1(Знач Структура)
	Структура.Тест = "Пока";
КонецПроцедуры

Комментами по коду отметил, что после выполнения процедуры "ИзменитьСтруктуру1", вернувшись обратно в процедуру "Тест1", неожиданно обнаруживаем, что значение "Структура.Тест" поменялось с "Привет" на "Пока". В чем же дело? Мы же установили "Знач" во второй процедуре и значение не должно было вернуться обратно! Перечитываем этот кусок документации еще раз: "Однако необходимо помнить", пробуем моделировать еще раз, но в этот раз попытаемся изменить тип формального параметра "Структура", присвоив новое значение переменной, тип число, значение = 300:

&НаСервере
Процедура Тест1()
	
	Структура = Новый Структура;
	Структура.Вставить("Тест", "Привет"); // Структура.Тест = "Привет"
	
	// После вызова и выполнения процедуры
	// Все еще Структура.Тест = "Пока", хотя мы изменили переменную на число 300
	ИзменитьСтруктуру1(Структура);
	
	Результат = Структура.Тест; // Структура.Тест = "Пока"
	Сообщить(Результат);
	
КонецПроцедуры

&НаСервере
Процедура ИзменитьСтруктуру1(Знач Структура)
	
	Структура.Тест = "Пока";
	Структура = 300; // Абстрактное число
	
КонецПроцедуры

И что же мы видим? Переменная Структура не поменяла тип. Как была тип = Структура, так и осталась. Знач отработало корректно. Но при этом внутри самой структуры значение элемента все-таки поменялось на "Пока". Так отработало Знач или нет?!!

Отсюда делаем логический вывод: Когда используем в передаваемом параметре не примитивные объекты (Строка, Число и т.п.), но агрегированные объекты (Структура, Массив и т.п.) и после передачи формального параметра  с использованием "Знач" уже не получится изменить сам фактический параметр в точке вызова, но используя свойства/методы агрегированного объекта, в данном случае Структура, можно менять значения элементов, которые радостно вернутся через "Знач" обратно в фактический параметр в точке вызова! В чем мы наглядно и убедились. Теперь становится более понятно, что имеется ввиду в тексте документации: "Однако необходимо помнить"

Пример2

Попробуем сразу перейти к смене режима управления:

4.7.4.3. Вызов с передачей управления с клиента на сервер и смоделировать тот же самый пример, чтобы посмотреть, что будет в данном случае.

&НаКлиенте // Внимательно в этой строке
Процедура Тест2(Команда)
	
	Структура = Новый Структура;
	Структура.Вставить("Тест", "Привет"); // Структура.Тест = "Привет"
	
	// После вызова и выполнения процедуры
	// Неожиданно остается Структура.Тест = "Привет". Почему? Давайте разбираться далее в тексте публикации.
	ИзменитьСтруктуру1(Структура);
	
	Результат = Структура.Тест;
	Сообщить(Результат);
	
КонецПроцедуры

&НаСервере // Внимательно в этой строке. Изменилось управление с клиента на сервер
Процедура ИзменитьСтруктуру1(Знач Структура)
	Структура.Тест = "Пока";
КонецПроцедуры

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

Прочтем документацию:

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

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

Т.е. при смене управления с клиента на сервера или с сервера на клиент 

всегда передаются копии параметров

Логический вывод на основе примера: значит ни о какой передаче по ссылке речи быть уже не может и указание "Знач" блокирует уже возврат, как самой новой созданной копии во второй процедуре, так и его элементов, даже если мы изначально передавали в точке вызова агрегируемый объект (Структура, Массив и т.п.), именно поэтому в точке вызова мы видим неизмененный фактический параметр, сам объект и значения его элементов.

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

Пример3

4.7.4.2. Вызов без передачи управления с клиента на сервер

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

&НаСервере // Внимательно в этой строке
Процедура Тест3()
	
	Структура = Новый Структура;
	Структура.Вставить("Тест", "Привет"); // Структура.Тест = "Привет"
	
	// После вызова и выполнения процедуры
	// Ожидаем увидеть тут Структура.Тест = "Пока"
	// Но неожиданно прилетает обратно Структура.Тест = "ПриветПока".
	// Почему? Давайте разбираться далее в тексте публикации.
	ИзменитьСтруктуру2(Структура);
	
	Результат = Структура.Тест;
	Сообщить(Результат);
	
КонецПроцедуры

&НаСервере // Внимательно в этой строке. Смены управления нет.
Процедура ИзменитьСтруктуру2(Знач Структура)
	
	Структура.Тест = "ПриветПока"; // 2. А на самом деле вернется это значение
	
	Структура = Новый Структура;
	Структура.Вставить("Тест", "Пока"); // 1. Якобы вернется это значение обратно
	
КонецПроцедуры

А что вообще происходит?!! Мы же изменили значение элемента во второй вызываемой процедуре с "ПриветПока" на "Пока" и логично было бы увидеть это значение в точке вызова в первой процедуру, но тем не менее мы видим значение "ПриветПока". Единственное разумное объяснение, которое я здесь вижу это - в момент передачи в параметр передан по значению указатель на структуру (или это ссылка на нее же?)
Т.к. это ссылочный тип, то несмотря на передачу его по значению, модификация структуры внутри вызванной второй процедуры видна и снаружи. А вот присвоение другого значения (благодаря передаче по значению) не влияет на переменную снаружи вызова - это мы обсуждали выше в Примере1, т.е. мы уже не сможем Структуру заменить на Массив например, или на Число и т.п.

Но простите, ведь мы же по отладке видим во второй вызванной процедуре, что Структура.Тест получила новое значение = "Пока". А вот тут можно объяснить так - без смены контекста (во второй процедуре) мы работаем с тем же самым объектом. Но при возвращении в исходную первую процедуру он берёт изначальный указатель, который был до вызова второй процедуры. Как тебе такое, Илон Маск?))

UPD_20250111: Пояснение в комментах, от коллеги по цеху, Андрея Капустина:

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

Пример4

4.7.4.3. Вызов с передачей управления с клиента на сервер

Обратимся дальше к документации и прочитаем еще один нюанс:

  • Если для нескольких формальных параметров указывается одно и то же фактическое значение, то создается столько копий фактического значения, для скольких формальных параметров используется значение.
  • Если в качестве формальных параметров указано значение одной и той же переменной, то после возврата управления с сервера значение этой переменной будет установлено в значение самого правого формального параметра (без модификатора Знач), который изменялся в вызываемой функции.
&НаКлиенте // Внимательно в этой строке
Процедура Тест4(Команда)
	
	Структура = Новый Структура;
	Структура.Вставить("Тест", "Привет"); // Структура.Тест = "Привет"
	
	// После вызова и выполнения процедуры
	// Какое значение вернется теперь в Структура.Тест?
	// Вернется Структура.Тест = "Пока2"
	// Почему? Давайте разбираться далее в тексте публикации.
	ИзменитьСтруктуру3(Структура, Структура, Структура);
	
	Результат = Структура.Тест;
	Сообщить(Результат);
	
КонецПроцедуры

&НаСервере // Внимательно в этой строке. Изменилось управление с клиента на сервер
Процедура ИзменитьСтруктуру3(Структура, Структура2, Знач Структура3)
	
	Структура.Вставить("Тест", "Пока");
	Структура2.Вставить("Тест", "Пока2");
	Структура3.Вставить("Тест", "Пока3");
	
КонецПроцедуры

Сначала даже не смог понять, что написано вообще здесь:

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

Что?!! Смотрим в код внимательно и понимаем, что в момент вызова, так как происходит смена управления, создается отдельная копия формального параметра из одного фактического параметра, ну тут вроде уже все понятно. Пришли во вторую процедуру, выполнили изменения каждого параметра, хотим вернуться назад в первую процедуру. А какое значение теперь укладывать в Структура.Тест? Вот тут и становится более понятной документация = возьмется самое крайнее правое значение формального параметра без Знач, т.е. значение из параметра Структура2.Тест = "Пока2".

UPD_20250111: Пример5

4.7.4.3. Вызов с передачей управления с клиента на сервер

Попробуем смоделировать тот же пример, добавив еще 1 формальный параметр и поменяв их местами, вклинив параметр со Знач по середине:

&НаКлиенте // Внимательно в этой строке.
Процедура Тест5(Команда)
	
	Структура = Новый Структура;
	Структура.Вставить("Тест", "Привет"); // Структура.Тест = "Привет"
	
	// После вызова и выполнения процедуры
	// Какое значение вернется теперь в Структура.Тест?
	// Вернется Структура.Тест = "Пока4"
	// Почему? Давайте разбираться далее в тексте публикации.
	ИзменитьСтруктуру4(Структура, Структура, Структура, Структура);
	
	Результат = Структура.Тест;
	Сообщить(Результат);
	
КонецПроцедуры

&НаСервере // Внимательно в этой строке. Изменилось управление с клиента на сервер
Процедура ИзменитьСтруктуру4(Структура, Структура2, Знач Структура3, Структура4)
	
	Структура.Вставить("Тест", "Пока");
	Структура2.Вставить("Тест", "Пока2");
	Структура3.Вставить("Тест", "Пока3");
	Структура4.Вставить("Тест", "Пока4");
	
КонецПроцедуры

Как мы видим наглядно, документация отработала, как заявлено. Возвращено обратно крайнее правое значение без Знач.

Есть еще один кусок документации, который я сам не могу до конца понять:

4.7.4.3. Вызов с передачей управления с клиента на сервер

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

Тут опять же рассуждаю чисто логически, опираясь на саму же документацию:

Этого пункта в принципе быть не может априори, потому что нам сказано, что при смене управления с клиента на сервер или с сервера на клиент ВСЕГДА передаются копии параметров! О какой тогда ссылочности здесь вообще может вестись речь? Ссылка тут бессмыслена априори. Потому что это ВСЕГДА разные машины при смене управления, значит не можем задействовать одну и ту же область памяти компа (даже при файловом варианте базы нам сказано, что принцип клиент-серверности не изменяется в платформе). Значит логично предположить, что эта часть документации неверная либо она досталась в наследство от предыдущих вариантов платформы? А что ВЫ думаете по поводу этого пункта. Велкам ту комментс.

Мой коллега Сергей Шикуткин ответил так:

Логика такая: нужно вернуться во времена когда не было клиент-сервера, а всë выполнялось в одном контексте. Но раз это есть, то, возможно, когда только внедрили клиент-сервер, возникла такая особенность и поэтому еë добавили в документацию. А потом поведение пофиксили.

Фух! Ну и как вам?

Данная публикация создана для того, чтобы наглядно можно было более детальнее разжевать куски документации, потому что иногда ее нужно по-моему читать под кокаином)).

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

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

Пожелания, замечания, предложения - оставляйте в комментах.

Найдете ошибку? - Пишите в комментах. Исправлю.

Я всегда готов прислушаться к вашей критике.

Лучшая ваша благодарность - плюс на статью.

Обработку тестировал на 1С:Предприятие 8.3 (8.3.25.1374)

UPD_20250110: Думаю, надо добавить ссылку на эту статью. Она очень полезна. По ссылке или по значению? Ключевое слово Знач и с чем его едят

См. также

Механизмы платформы 1С Программист Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.

14.01.2025    2797    dsdred    30    

67

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    9324    bayselonarrend    20    

158

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    6835    dsdred    18    

80

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Бесплатно (free)

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

24.01.2024    21520    YA_418728146    26    

73

Механизмы платформы 1С Программист Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    24905    SeiOkami    48    

136
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. ubnkfl 10.01.25 10:45 Сейчас в теме
Спасибо за статью!
Плюс вам не могу поставить, т.к. "Ошибка! Для голосования необходимо быть автором или иметь подписку Инфостарт PRO."
ArchAhper; pavlov_dv; user2114782; t278; ardn; rpgshnik; VAAngelov; +7 Ответить
2. VAAngelov 504 10.01.25 11:14 Сейчас в теме
(1) Да. Это новые правила ИС. Вам спасибо за отзыв. Я старался.
ardn; v8_088; +2 Ответить
3. dhurricane 10.01.25 11:22 Сейчас в теме
В дополнение хотелось бы упомянуть статью, по которой я разбирался в тонкостях работы ключевого слова "Знач" в контексте клиент-серверных вызовов:
По ссылке или по значению? Ключевое слово Знач и с чем его едят
ArchAhper; artbear; bayselonarrend; VAAngelov; +4 Ответить
4. VAAngelov 504 10.01.25 11:25 Сейчас в теме
(3) О да. Эта статья была тоже очень полезна. Забыл ее сразу включить в публикацию. Сейчас добавлю в конце. Думаю это логично собирать все по взаимосвязям в одно место. Благодарен и вам!
5. DmitryKSL 157 10.01.25 14:46 Сейчас в теме
Но простите, ведь мы же по отладке видим во второй вызванной процедуре, что Структура.Тест получила новое значение = "Пока". А вот тут можно объяснить так - без смены контекста (во второй процедуре) мы работаем с тем же самым объектом. Но при возвращении в исходную первую процедуру он берёт изначальный указатель, который был до вызова второй процедуры. Как тебе такое, Илон Маск?))


Я думаю тут нет ничего удивительного. Объяснение простое. Возьмем например Слайс на GO. По сути слайс это и есть структура, которая внутри содержит указатель на массив. По умолчания слайс передается в функцию как значение. И это точная копия слайса, по сути еще одна структура в памяти по другому адресу, которая внутри содержит тот же указатель на массив.
В 1С видимо похожая история. Структура на входе по ЗНАЧ это новая структура. Предположу что ее поле внутри хранится как указатель. Поэтому меняя поле в ДРУГОЙ структуре, мы меняем его и в первой! Оно находится по тому же адресу. Это же объясняет почему такая фишка не работает между клиентом и сервером. Естественно вы с клиента не сможете прочитать память сервера и наоборот.
VAAngelov; +1 Ответить
8. VAAngelov 504 10.01.25 16:28 Сейчас в теме
(5) Благодарю за пояснения!
6. sashocq 193 10.01.25 15:31 Сейчас в теме
Есть ещё один существенный нюанс, который почему-то упускают из вида: объём передаваемых данных.
При вызове с клиента серверной процедуры с передачей большого значения (большая структура, массив и т. п.) если в параметре не указано Знач, то даже если значение не менялось, оно всё равно вернётся целиком. Так что если вам не нужно, чтобы сервер обратно его присылал, укажите Знач.
Прикрепленные файлы:
Тест Знач.epf
zqzq; bulpi; VAAngelov; +3 Ответить
7. sashocq 193 10.01.25 15:35 Сейчас в теме
(6) Вызов со Знач (почему-то в предыдущее сообщение не прикреплялось корректно)
Прикрепленные файлы:
9. VAAngelov 504 10.01.25 16:30 Сейчас в теме
(6) По делу. Соглашусь. Благодарю. Вечерком еще гляну вашу обработку.
10. Alxby 1122 10.01.25 17:36 Сейчас в теме
(6) Вообще говоря, стандарты рекомендуют для передачи значений с сервера на клиент использовать функции с возвращаемыми значениям и не использовать возврат через параметры https://its.1c.ru/db/v8std#content:487:hdoc
12. sashocq 193 10.01.25 18:21 Сейчас в теме
(10) И это правильно. Цель: именно минимизация объёма траффика от сервера к клиенту.
Мой опыт говорит о том, что в 99% случаев разработчики вообще не обращают на это внимания. Я, честно, почти не видел ключевого слова Знач в описаниях параметров даже в типовых конфигурациях, не говоря уже доработках сторонних разработчиков.
Вот взял УТ 11 из последних, открыл первый попавшийся модуль ВызовСервера — ни одного Знач.
Прикрепленные файлы:
VAAngelov; +1 Ответить
38. TMV 14 12.01.25 21:25 Сейчас в теме
(12) вы, кажется, лукавите
Прикрепленные файлы:
11. Alxby 1122 10.01.25 17:42 Сейчас в теме
Многое становится понятным, если представить, что Структура (Массив,... etc.) это адрес области памяти, в которой находятся данные структуры. Передача структуры по значению или по ссылке - это передача адреса или переменной, содержащей адрес. Логично, что в обоих случаях, обращаясь по этому адресу мы попадаем к одним и тем же данным. Так же очевидно, что области памяти на клиенте и на сервере разные по определению, а значит передача только адреса бессмысленна, надо передавать все данные, которые лягут в другую область памяти.
VAAngelov; +1 Ответить
18. VAAngelov 504 11.01.25 11:06 Сейчас в теме
(11) Благодарю за пояснения. Они очень полезны.
13. artbear 1565 10.01.25 20:21 Сейчас в теме
Просто привыкайте всегда использовать Знач для параметров - простой и легкий прием.
- и для клиент-серверной работы полезно
- и для большинства типов нет потери производительности

могут быть трудности только с длинными\толстыми строками, копирование которых может приводить к проблемам с производительностью, да и то далеко не всегда
sashocq; zqzq; VAAngelov; +3 Ответить
17. Alxby 1122 10.01.25 21:34 Сейчас в теме
(13) Эх, если бы было все так просто... А циклические ссылки внутри сложной структуры? Клиент-серверная передача (или хотя бы просто сериализация) вызывает ошибку. Но это полбеды, в платформе хотя бы есть средства для поиска циклических ссылок. А вот множественные ссылки внутри сложной структуры (не циклические) простым способом найти нельзя, но при передаче с клиента на сервер или обратно они передаются неправильно - прилетает структура совсем другого формата. Единственный выход - делать свою сериализацию, отличную от платформенной...
24. user894822 11.01.25 15:25 Сейчас в теме
(17) Мне приходилось сталкиваться с такой проблемой, нужно было хранить сложный граф в памяти. Выход таков: все объекты хранить в массиве, все ссылки на объекты - в виде индексов этого массива.
29. Alxby 1122 11.01.25 16:45 Сейчас в теме
(24) Да, это наверное самый простой и надежный способ. Но в нем нет защиты от "битых" индексов-ссылок и есть проблемы с изменением индексов при вставке/удалении/сортировке. Вместо массива иногда лучше использовать соответствие, но у в нем нет упорядочивания. Для упорядочивания приходится заводить дополнительный индексный массив.
30. user894822 11.01.25 18:17 Сейчас в теме
(29) Не вопрос, можно и соответствие, если подобрать подходящую форму ключа. Если обобщить решение, то: объекты должны храниться в коллекции и ссылки на них должны храниться только в виде ключей этой коллекции. В этом случае сериализация и десериализация будут проходить без проблем.
14. partizand 139 10.01.25 20:40 Сейчас в теме
Могу предложить простое объяснение.
Передача по Знач - это все же передача по ссылке, но с модификатором const.
Тогда логично невозможность изменить само значение, но возможно изменение внутреннего содержимого.
А передача клиент сервер это всегда копирование.
В примере с несколькими одинаковыми параметрами только не ясно. Получается параметр знач копируется.
VAAngelov; +1 Ответить
19. VAAngelov 504 11.01.25 11:10 Сейчас в теме
(14) Соглашусь с вышесказанным вами.
Для примеров с несколькими одинаковыми параметрами сделаю еще пару тестов. Хорошая мысль. Давайте попробуем их поменять местами и проверим, как все-таки выполняется механизм, но что-то мне подсказыывает, что будет все-таки возвращаться крайний справа из формальных параметров без Знач.
Сейчас займусь моделированием, допилю статью еще парой вариантов и перевыложу обработку.
Меня тоже интересует этот сценарий.
15. partizand 139 10.01.25 20:46 Сейчас в теме
В примере с несколькими параметрами ещё важно кто последний установил параметр. У вас только один вариант. А можно поменять присвоение местами.
VAAngelov; +1 Ответить
21. VAAngelov 504 11.01.25 11:34 Сейчас в теме
(15) Все-таки возвращается крайнее справа значение без Знач.
Прикрепленные файлы:
22. VAAngelov 504 11.01.25 11:38 Сейчас в теме
(15) Еще вариант:
Прикрепленные файлы:
23. VAAngelov 504 11.01.25 11:45 Сейчас в теме
(15) Еще вариант с заменой местами и вклиниванием параметра со Знач посередке:
Прикрепленные файлы:
28. user894822 11.01.25 16:12 Сейчас в теме
(15) Если вызов происходит в рамках одного пространства памяти, то так и есть. Но при серверном вызове уже только платформа решает, в каком порядке вернуть значения.
35. VAAngelov 504 12.01.25 10:51 Сейчас в теме
(28) Сразу не могу понять как это, хотелось бы наглядный пример какой-то. Если несложно.
43. user894822 13.01.25 15:24 Сейчас в теме
(35) Если при вызове не происходит перехода между клиентом и сервером, то переменная вызывающей стороны изменяется в момент присваивания ее значения в вызываемой процедуре. Поэтому, если несколько возвращаемых параметров ссылаются на одну переменную, то в ней останется то значение, которое было присвоено последним.

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

&НаКлиенте
Процедура Вызывающая()

	Перем А;
	
	ПолучитьХУ(А, А); // А = 2
	
	ПолучитьУХ(А, А); // А = 1

КонецПроцедуры

&НаКлиенте
Процедура ПолучитьХУ(Х, У)

	Х = 1;
	У = 2;

КонецПроцедуры

&НаКлиенте
Процедура ПолучитьУХ(Х, У)

	У = 2;
	Х = 1;

КонецПроцедуры
Показать
16. partizand 139 10.01.25 20:49 Сейчас в теме
И в примере, где создаётся новая структура все верно. Ведь вы создали новую область памяти с новой ссылкой. Просто ей присвоилось имя от другой области. А параметр остался по своему адресу, но обратится к нему вы уже не можете, т.к. затерли имя. Потенциальная утечка памяти.
VAAngelov; +1 Ответить
20. VAAngelov 504 11.01.25 11:11 Сейчас в теме
(16) Вот это прям хорошее замечание и пояснение. Спасибо. Думаю ваш комментарий заслуживает того, чтобы его включить в статью. Мне нравится это объяснение. Оно последовательно логичное. Хорошее объяснение.
25. user894822 11.01.25 15:34 Сейчас в теме
(16) Утечки памяти не будет. Платформа следит за использованием указателей и освобождает память автоматически.
37. rozer 312 12.01.25 16:29 Сейчас в теме
(16) таких примеров много когда используется одно имя, например, объявить массив Х и в цикле, заполнить данными и добавить в другой массив Y. В итоге мы используем одно и тоже имя переменной Х но это разные массивы в Y...
VAAngelov; +1 Ответить
26. user894822 11.01.25 15:51 Сейчас в теме
Всё становится довольно прозрачным, если помнить несколько простых вещей:
1. Передача без Знач - это передача ссылки (указателя) на переменную, передача со Знач - это передача копии переменной.
2. Переменная сложного типа (массив, структура и т.п.) - на самом деле является лишь указателем на область данных в памяти. Копирование указателя не приводит к копированию области памяти, все копии указателя указывают на одну и ту же область памяти.
3. При передаче управления между клиентом и сервером происходит сериализация сложного объекта (массива, структуры и т.п.) и затем воссоздание его копии путем десериализации.
Для тех, у кого есть опыт работы на с/с++, всё это представляется вполне естественным.
VAAngelov; +1 Ответить
31. VAAngelov 504 11.01.25 18:38 Сейчас в теме
(26) Доступно и понятно. Спасибо за пояснения. Очень толково сказано.
27. user894822 11.01.25 16:02 Сейчас в теме
Есть ещё интересные особенности при работе с временным хранилищем.
На практике выяснил, что функция ПолучитьИзВременногоХранилища возвращает не копию объекта, а указатель на объект во временном хранилище. Если изменить содержимое полученного объекта, то при повторном вызове ПолучитьИзВременногоХранилища с тем же адресом, мы получим изменённый объект.
Отсюда также следует вывод, что объекты во временном хранилище хранятся в "первозданном", а не сериализованном виде, сериализация временного хранилища происходит только в момент передачи управления между клиентом и сервером.
VAAngelov; +1 Ответить
32. user925427 130 11.01.25 23:30 Сейчас в теме
Вывод: проверяйте ваши идеи в отладке, если собираетесь использовать в алгоритме изменённые значения параметров. Автору респект за поднятую тему, дополняющую документацию.
VAAngelov; +1 Ответить
33. VAAngelov 504 11.01.25 23:41 Сейчас в теме
Благодарю. Я лишь хотел просто осветить темное место, подняв эту тему.
34. alex_sayan 54 12.01.25 10:39 Сейчас в теме
Статья ни о чём. Банальный пересказ документации. Автор мог бы развить тему, написать как и зачем неизменяемость и передачу по ссылке/значению применяют в других языках... но почему-то не сделал этого
36. VAAngelov 504 12.01.25 10:55 Сейчас в теме
(34) Спасибо за комментарий. Я бы с удовольствием развил тему, если бы увидел ещё сценарии. А других языков я просто не знаю.
39. Nio 72 13.01.25 09:19 Сейчас в теме
В свое время готовил публикацию, но не пропустили. Попробую высказать кратко.

Структура1 = Новый ФиксированнаяСтруктура("Значение, Массив"
										,"Значение структуры 1"
										,Новый Массив);
										
Структура2 = Новый Структура(Структура1);

Структура3 = Новый Структура(Структура1);
Структура3.Значение="Значение структуры 2";
Структура3.Массив.Добавить("Элемент массива");

Сообщить(Структура1.Массив.Количество());
Сообщить(Структура2.Массив.Количество());
Сообщить(Структура3.Массив.Количество());
Показать


Кто без подсказке сможет сразу сказать что будет сообщено пользователю?

Для меня это явилось полной неожиданностью, но я получил

1

1

1
41. DmitryKSL 157 13.01.25 13:50 Сейчас в теме
(39)
Интересно что вы ожидали? Вы создаете структуру на основании другой структуры и копируете все свойства. Массив у них общий, т.к. хранится в структуре как указатель.
40. Sashares 35 13.01.25 13:31 Сейчас в теме
Можно предложить дополнить статью про несколько не очевидную особенность работы асинх процедур/функций.
Т.к. в асинх процедурах параметры передаются по значению, а по ссылке передать ничего нельзя, то если параметром передается агрегатный объект, его также можно изменять, и получить в вызываемой функции измененный объект.
Например, передается реквизит формы таблица значений, в асинх функции она заполняется, и по завершению фукнции, таблица будет заполнена.
VAAngelov; +1 Ответить
44. user894822 13.01.25 15:40 Сейчас в теме
46. Sashares 35 14.01.25 10:22 Сейчас в теме
(44) Я не про то, что по значению передаются параметры, а про то, что даже в параметрах переданных по значению, можно вернуть данные.
47. user894822 14.01.25 11:25 Сейчас в теме
(46) Здесь необходимо в точности понимать, как это работает.
Выход из асинх-функции происходит ДО того, как ее выполнение полностью завершится. Выход произойдет в первой же точке ожидания. Соответственно, если асинх-функция модифицирует структуру, переданную ей в параметре, то на выходе мы получим только те модификации, которые были сделаны до первой точки ожидания. Далее всё зависит от того, собираемся ли мы использовать изменения структуры до или после выполнения обещания.

&НаКлиенте
Асинх Процедура Вызывающая()

	С1 = Новый Структура("Ответ");
	ОбещаниеОтвета = ПолучитьОтвет(С1);
	Сообщить("Ответ: "+С1.Ответ); // Ответ: Нет ответа
	
	Ждать ОбещаниеОтвета;
	Сообщить("Ответ: "+С1.Ответ); // Ответ: Да/Нет
	
	С2 = Новый Структура("Ответ");
	Ждать ПолучитьОтвет(С2);
	Сообщить("Ответ: "+С2.Ответ); // Ответ: Да/Нет
	
КонецПроцедуры

&НаКлиенте
Асинх Функция ПолучитьОтвет(С)

	С.Ответ = "Нет ответа";
	
	Ответ = Ждать ВопросАсинх("Выберите ответ", РежимДиалогаВопрос.ДаНет);
	Если Ответ = КодВозвратаДиалога.Да Тогда
		С.Ответ = "Да";
	Иначе
		С.Ответ = "Нет";
	КонецЕсли;
	
	Возврат Неопределено;

КонецФункции
Показать


С асинх-процедурой несколько иначе: она не может вернуть обещание, поэтому мы не можем Ждать ее полного завершения. Соответственно, мы не получим тех изменений в структуре, которые совершатся после первой точки ожидания.
VAAngelov; +1 Ответить
48. Sashares 35 14.01.25 12:44 Сейчас в теме
(47) Я в курсе как это работает, поэтому и предложил в статье описать это.
VAAngelov; +1 Ответить
49. VAAngelov 504 14.01.25 16:31 Сейчас в теме
(48) Я абсолютно не против. Если удастся выкроить время - постараюсь рассмотреть и ваше предложение и дополнить статью. Но говорю сразу, не обещаю. Вначале надо еще и самому разобраться и понять, прежде чем вещать для публики.
42. kuzyara 2105 13.01.25 13:56 Сейчас в теме
ещё интересно было бы проверить эти кейсы в интерпретаторе реализованном на javascript (веб-клиент) и в интерпретаторе реализованном на .net c# (onescript) - отличается ли поведение от сишного кода?
45. VAAngelov 504 13.01.25 18:05 Сейчас в теме
(42) Запилите статью?) Буду очень рад почитать результаты.
Оставьте свое сообщение