LINUX.ORG.RU

В каких ЯПах существуют функции, способные возвращать несколько значений?

 , , ,


0

0

Вроде такого:

int, double, double add (int a) {
    return (a+1), (a+2.2), (a+3.3);
}

int a = 8;
int b;
double c, d;

b, c, d = add(a);

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

Ответ:

Список япов:

  1. go
  2. lua
  3. haskell
  4. rust и проч.

Реализованы - через тульпы/структуры, поэтому в abi ничего не меняется. Но есть и более интересные вариации: так, например, в SBCL первые три возвращаемых значения передаются через регистры (RDX, RDI, RSI), а остальные через стек



Последнее исправление: x86- (всего исправлений: 6)
Ответ на: комментарий от x86-

В каждой реализации CL свои конвенции вызова, передачи параметров. В CL чтобы принять множественные результаты используется (multiple-value-bind) для биндинга переменных, (multiple-value-call ...) для вызова какой-то функции над вовзращаемыми значениями. Компилятор знает, в каком порядке и откуда вытаскивать результаты.

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

Знаю, интересовал именно SBCL. Но все, уже нашла http://www.sbcl.org/sbcl-internals/Full-Calls.html#Full-Calls

А, нет, здесь речь о параметрах, а не возвращаемых значениях.

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

А, нет, здесь речь о параметрах, а не возвращаемых значениях.

Вот это релевантно вопросу в топике. http://clhs.lisp.se/Body/s_multip.htm . Особенности реализаций в стандарте не описывается.

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

соглашения о совместимости.

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

Не могу найти оные

x86-
() автор топика
Ответ на: комментарий от x86-

Не могу найти оные

Да нет изложения, так как стандарт не ограничивает в выборе. Да и архитектур куча. Смотреть лучше в исходнике (это для x86-64): https://github.com/sbcl/sbcl/blob/10f8f9c9d328b8cd03fbae81408380512de4f9a3/sr...

UPD. И это https://github.com/sbcl/sbcl/blob/10f8f9c9d328b8cd03fbae81408380512de4f9a3/sr...

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от x86-

Не могу найти оные

искать надо по сигнатурам - ABI, calling conventions, register allocation.

как уже выше сказано - там всякий волен делать что хочет. лишь бы код получался пооптимальный. например если функция принимает первый параметр в rax, и возвращает результат в rax, то вызов вида - f(ff(fff(100))) вообще не требует кода передачи параметра (кроме кода для 100), поскольку параметр уже будет в rax.

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

общего стандарта естессно нет.(потому что ..откуда ему взяться то?)

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

Ну и вот словами. https://github.com/sbcl/sbcl/blob/d35ad6f9bee212499cb827fec3195bf2064c10a2/do... , но выглядит, что это писали еще для x86, но я так понимаю, что принцип не поменялся. ECX - число возвращаемых значений передает (тип fixnum, то есть число сдвинуто влево на 1 бит, то есть умножено на два).

Zubok ★★★★★
()

а если в ретюрне нужно явно в массив завернуть это считается?)

#ruby
f = -> { [1, 2] }
a, b = f.call

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

а если в ретюрне нужно явно в массив завернуть это считается?)

Нет, все же решила не считать те языки, где происходит явная (де-)структуризация как например std::tuple в с++ или обертка в тульпу в питоне. Засчитываются языки вроде go, где по-честному на уровне языка возвращается несколько отдельных значений

x86-
() автор топика
Ответ на: комментарий от x86-

Нет, все же решила не считать те языки, где происходит явная (де-)структуризация…

понимала б чаво…

в нормальном сильно типизированном языке это тип кортеж, он же - tuple. и возвращает функция никакие не «несколько переменных», а кортеж. а поскольку есть тип - кортеж, то существуют и переменные типа кортеж. тогда функция вида ff()->(int,int,int)

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

то, что нарисовано в го - это костыль он же синтсахар, и там нет кортежей, насколько я помню.

просто возврат из функции нескольких результатов, это вообще не то, ради чего стоило городить этот огород.

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

Не важно, костыли это или нет, вопрос был теоретический - существует ли это где-то - реализации возврата множественных значений без промежуточных кортежей на

а) уровне языка

б) уровне скомпилированного машинного кода

В этом заключался вопрос из заголовка. Подходящие по критерию примеры - (1) го, (2) sbcl

x86-
() автор топика

У процессоров нету понятия функций, а значит и возвращать ничего нельзя.

BceM_IIpuBeT ★★☆☆☆
()

Питон, С++-17.

Тред не читал.

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

без промежуточных кортежей на

(1) го,

нет.

единственный пример, который подходит (кроме «функций», хотя есть и функциональные варианты), и который приводили - форт и все его веселое семейство. И на уровне языка, и на уровне машинного кода. Там вообще по-другому никак. Все остальные так или иначе возвращают «множественные значения» через структуры.

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

форт и все его веселое семейство

In Fortran, a subroutine "returns" everything you pass to it. You can think of it almost like a C Macro. In this:

 SUBROUTINE CALC(A,B,C, SUM,SUMSQ)

The subroutine "returns" A, B, C, SUM, and SUMSQ. (Really, it just modifies the values passed to it in-place.)

In contrast, FUNCTION works like a C function, creating locals and returning a single value, which is what people used to more modern languages typically expect.

Не подходит по критериям. Subroutine - то же самое, что и простая сишная функция с передачей аргументов по указателю, Function - возвращает только одно значение.

x86-
() автор топика
Ответ на: комментарий от x86-

In Fortran

Форт с Фортраном спутать? Да, это мощно, такого даже метапрог не сумел.

anonymous
()
Ответ на: комментарий от Zubok

А, лол, не приходилось встречать ранее.

x86-
() автор топика
Ответ на: комментарий от anonymous

единственный пример, который подходит (кроме «функций», хотя есть и функциональные варианты), и который приводили - форт и все его веселое семейство.

что значит единственный? Common Lisp же. Возврат множества значений из функции (values ...) — это конструкция языка, которая не возвращает результат в каком-то композитном типе типа списка, структуры, вектора, а именно как бы по отдельности укладывает в нужное место. Если спросить про тип, который функция возвратила, то будет тип первого значения. Чтобы прочесть и другие результаты, надо использовать специально обученные конструкции для этого (выше все приведены):

CL-USER> (type-of (values "12" 'a 3))
(SIMPLE-ARRAY CHARACTER (2))
CL-USER> (type-of (values 'a "12" 3))
SYMBOL
CL-USER> (type-of (values 3 'a "12"))
(INTEGER 0 4611686018427387903)
CL-USER> 
Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от Zubok

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

Без списка? Хм, не знал. Интересная фича, обязательно при случае (очередном подходе к станку CL) надо поглядеть на её внутренности.

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

Без списка?

Без списка, да. Даже тип соответствующий не существует. Просто multiple values. Фича как бы интересная, но служит, в общем-то, оптимизационным целям. Не создается в памяти композитный объект, отдельные результаты не cons-ятся, все передается локально.

CL-USER> (defun test-list () (list 11 "aa" 'a))
TEST-LIST
CL-USER> (defun test-values () (values 11 "aa" 'a))
TEST-VALUES
CL-USER> (test-list)
(11 "aa" A)
CL-USER> (test-values)
11
"aa"
A
CL-USER> (type-of (test-list))
CONS
CL-USER> (type-of (test-values))
(INTEGER 0 4611686018427387903)
CL-USER> (nth-value 1 (test-values))
"aa"
Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)

Во всех в которых есть алгебраические типы данных, то есть почти во всех.

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

Это и в CL есть: DESTRUCTURING-BIND

я знаю, что такое d-b, проблема только в том, что это отдельная сущность, в кложуре же деструктуризация first-class везде начиная от банального let

Здесь же другое - именно множественный результат.

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

Если ты не будешь делать multiple-value-bind, то функция первое значение возвратит.

спасибо, я в курсе, что такое лисп

anonymous
()
Ответ на: комментарий от Zubok

По сути своей values - это больше для оптимизации:

а, ну только если для оптимизации, больше я смысла в нём никакого не вижу

anonymous
()

Вот где этого нет, так это Java (или я не нашёл?). Вернуть несколько значений нельзя никак, ни через tuple, ни через параметры по ссылке (их нет). Даже Оберон и то выразительнее:

PROCEDURE SinCos(angle: REAL; OUT sin, cos: REAL);
X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.