Тип 'void'
От: _NN_  
Дата: 25.05.14 12:29
Оценка: 26 (3)
Насколько логично относиться к 'void' или 'Unit' как к обычному типу ?
Скажем, логично ли требовать чтобы код с обычными типами работал и с void ?

К примеру с типами все ясно

function f(a : number) : number {..}
function g() : number {..}
function h(c : number, d : number) {..}

var x = f();
f(g()); // OK
f(x); // OK
h(f(), g()); // OK


А с void ?
function f(a : void) {..}
function g(b : void) {..}
function h(c : void, d : void) {..}

var x = f();
f(g()); // OK ?
f(x); // OK ?
h(f(), g()); // OK ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Тип 'void'
От: hi_octane Беларусь  
Дата: 25.05.14 21:12
Оценка: 1 (1) +2
_NN>Насколько логично относиться к 'void' или 'Unit' как к обычному типу ?
_NN>Скажем, логично ли требовать чтобы код с обычными типами работал и с void ?

_NN>А с void ?

_NN>
_NN>function f(a : void) {..}
_NN>function g(b : void) {..}
_NN>function h(c : void, d : void) {..}

_NN>var x = f();
_NN>f(g()); // OK ?
_NN>f(x); // OK ?
_NN>h(f(), g()); // OK ?
_NN>


ОК, ОК, ОК.

Пока не рассматриваем случай Nullable<void>/void? который уже bool получается, и при этом попадает под требование работы с void как с обычными типами

Очевидно что a,b,c,d реально не используются — будет удобно, если любое значение которое не используется, будет приводиться к void и не компостировать мозг своим типом.

Основное удобство void как типа в Generic'ах. А то в C# эти Action<T> и Func<T> уже достали.

Как пример удобства — допустим у нас есть готовый Dictionary<TKey, TValue> лёгким движением руки через
var hashSet = new Dictionary<int, void>(); эта коллекция превращается в Set. При этом метод hashSet.Add(key : TKey, value : TValue), внезапно начинает компилироваться с одним аргументом hashSet.Add(5), так как void в недостающие места компилятор и сам подсунуть может. Красота

Как элемент мозгового штурма, а что если в языке object будет наследником от void?
Re[4]: Тип 'void'
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.05.14 07:17
Оценка: +3
Здравствуйте, NeoCode, Вы писали:

NC>Думаю я немного ошибся: http://en.wikipedia.org/wiki/Unit_type

NC>unit — это "улучшенный void", и он же "0-tuple". Но все равно мне не нравится идея передавать в функцию, принимающую void, "результат" другой функции, возвращающей void.
По-моему, вы слишком много думаете о конкретных типах. Ценность "единого void" — в обобщённом коде.
Вот простой пример: мы хотим сделать тип "типизированный словарь", который хранит отображение ключ->значение.
При этом подразумевается уникальность ключа и бла-бла-бла.
Если у нас есть полноценная поддержка типа void, то тип "множество значений" получается как тривиальный частный случай: Set<TKey> == Dictionary<TKey, void>. А если нет (как, скажем, в дотнете), то нам нужно городить два совершенно несвязанных интерфейса для ISet<TKey> и IDictionary<TKey, TValue>.
Опять же, всякие ФВП приходится писать дважды — для функций, возвращающих значение, и для невозвращающих значение.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Тип 'void'
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 26.05.14 06:34
Оценка: +2
Здравствуйте, NeoCode, Вы писали:

NC>Путаница в том, что если void — это отсутствие параметра, а мы туда все-же передаем "возврат" другой функции, возвращающей void,


А вот не надо его определять как отсутствие параметра. От этого только одни проблемы и неудобства.
Вспомните математику: функция есть отображение из чего-то в чего-то, не бывает в принципе функций, которые ничего не принимают или ничего не возвращают. Когда вместо void используется unit, он же (), его можно и пустым туплом считать, все получается логично и удобно. А иначе возникает масса специальных случаев, мешающих писать универсальный/обобщенный код.
Re[6]: Тип 'void'
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 27.05.14 05:57
Оценка: +2
Здравствуйте, NeoCode, Вы писали:

NC>
function foo(void, int, void);

NC>(такое может получиться, например, из шаблонной функции при подстановке void в параметры шаблона)
NC>Должен ли компилятор "сворачивать" ее к виду "foo(int)"?

Мой ответ: нет, ни в коем случае. От этого опять куча проблем и граблей.

И еще важный момент: нужно понимать, что f() — это не вызов функции без аргументов, а именно вызов с одним аргументом — (), он же void. Он потому так и называется (), не просто так. Поэтому f(void) не имеет никакого смысла, это же f (()), бессмысленная конструкция даже синтаксически.
А foo(void, int, void) принимает тупл из трех элементов, ни больше ни меньше.
Re: Тип 'void'
От: C.A.B LinkedIn
Дата: 25.05.14 15:01
Оценка: +1
Здравствуйте, _NN_, Вы писали:
_NN>Насколько логично относиться к 'void' или 'Unit' как к обычному типу ?
_NN>Скажем, логично ли требовать чтобы код с обычными типами работал и с void ?
Вполне логично, это означает "нет результата", пример использования в Scala:
def u():Unit = {}  
def i():Int = 1         

val t = if(...) f() else i()

t match{
  case _:Unit => println("Unit")
  case i:Int => println(i)}
Между тем,что я думаю,тем,что я хочу сказать,тем,что я,как мне кажется,говорю,и тем,что вы хотите услышать,тем,что как вам кажется,вы слышите,тем,что вы понимаете,стоит десять вариантов возникновения непонимания.Но всё-таки давайте попробуем...(Э.Уэллс)
Re[4]: Тип 'void'
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 26.05.14 04:54
Оценка: +1
Здравствуйте, NeoCode, Вы писали:

NC>В некоторых языках есть возможность возвращать несколько возвращаемых значений (кортеж). Т.е. возможно например такое

NC>
function foo() : int, float {return 10, 3.14;}

NC>x,y = foo();[/code]
NC>Если такое возможно, то захочется передавать возвращаемый кортеж вместо нескольких аргументов в другую функцию:
NC>
function bar(char c, int x, float f, string s) {}
NC>bar('q',foo(),"hello");

NC>кто-то скажет что это красиво, а я считаю что такое только запутает.

Тут в bar передаётся не (char*int*float*string), а (char*(int*float)*string) — это другой тип. Зачем их отождествлять?
Ce n'est que pour vous dire ce que je vous dis.
Re[9]: Тип 'void'
От: NeoCode  
Дата: 26.05.14 09:22
Оценка: +1
Здравствуйте, _NN_, Вы писали:

_NN>Ну сейчас невозможно вызвать функцию с передачей void значение. Такое невозможно сделать с другим типом

_NN>В принципе такое нужно только в обобщенном коде.
_NN>Возможно в обычном действительно вносит лишнюю путаницу.

Между обобщенным и обычным кодом не должно быть разницы, иначе это вообще полная фигня получится.
Re[11]: Тип 'void'
От: Klapaucius  
Дата: 28.05.14 13:05
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S>Тогда получается "...приходится писать бесконечное количество раз — для функций, принимающих 0 значений, 1 значение, 2 значения, и т.п."

S>А если ФВП способна работать с функцией, принимающей N аргументов, то она отлично справится и с N=0.

ФВП, работающая с функцией одного аргумента a -> b отлично со всем этим справляется, несколько параметров можно определять так a -> (c -> d) или (c,d) -> b и так далее. Возращающую несколько значений — a -> (c,d) и так далее. Функцию с одним параметром, с областью определения в одно значение (а привычные функции foo() как раз такие) соответственно () -> b, с областью значений в одно значение a -> () (это всякие void foo функции). С пустой областью определений Void -> b (Void — это пустой тип, не нужно путать его с void из мейнстрим языков, который вовсе не пустой и вообще называется Unit), такие тоже находят применение см. http://hackage.haskell.org/package/void-0.6.1/docs/Data-Void.html#v:absurd

S>Тогда проще отказаться от функций, не принимающих значение.


Ну да, что такое "функция не принимающее значение" вообще не очень понятно.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re: Тип 'void'
От: deniok Россия  
Дата: 25.05.14 14:16
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Насколько логично относиться к 'void' или 'Unit' как к обычному типу ?

_NN>Скажем, логично ли требовать чтобы код с обычными типами работал и с void ?

_NN>А с void ?

_NN>
_NN>function f(a : void) {..}
_NN>function g(b : void) {..}
_NN>function h(c : void, d : void) {..}

_NN>var x = f();
_NN>f(g()); // OK ?
_NN>f(x); // OK ?
_NN>h(f(), g()); // OK ?
_NN>


В языках с алгебраическими типами данных Unit — обычный тип, в котором имеется ровно одно значение. В Хаскелле, скажем, это значение () с типом (). То есть я могу написать
> let f () = ()
> :t f
f :: () -> ()
> let h () () = 42
> :t h
h :: Num a => () -> () -> a
> let x = f ()
> f x
()
> h (f ()) (f ())
42
Re: Тип 'void'
От: NeoCode  
Дата: 25.05.14 15:21
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Насколько логично относиться к 'void' или 'Unit' как к обычному типу ?

_NN>Скажем, логично ли требовать чтобы код с обычными типами работал и с void ?

void и unit это разные вещи.
void — это не тип, а скорее "кортеж без элементов". Поэтому, если фунция не имеет аргументов, в нее синтаксически нельзя передавать какие-бы то ни было аргументы, пусть даже void, точно также как в функцию с одним аргументом синтаксически нельзя передать два и более аргумента.

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

При попытке передать void и unit вместо например integer должны быть разные ошибки компиляции: передача void — это то же самое как если бы аргумент вообще не указали
function foo(int x, int y, int z){}
foo(1,,3);

а unit — указали, но другого (несовместимого) типа.
foo(1,"hello",3);
Re[2]: Тип 'void'
От: _NN_  
Дата: 26.05.14 03:40
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>Здравствуйте, _NN_, Вы писали:


_NN>>Насколько логично относиться к 'void' или 'Unit' как к обычному типу ?

_NN>>Скажем, логично ли требовать чтобы код с обычными типами работал и с void ?

NC>void и unit это разные вещи.

Боюсь люди получат тут разрыв шаблона если будет два пустых значения

NC>void — это не тип, а скорее "кортеж без элементов". Поэтому, если фунция не имеет аргументов, в нее синтаксически нельзя передавать какие-бы то ни было аргументы, пусть даже void, точно также как в функцию с одним аргументом синтаксически нельзя передать два и более аргумента.


NC>unit — это полноценный тип, имеющий единственное значние. Это значит, что если одна функция принимает тип unit, а другая возвращает, то вполне можно передать результат возврата — в точности как и с любым другим типом.

А почему тогда нельзя такое же провести с void ?
Компилятор за нас спрячет детали и выбросит пустые аргументы сам.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Тип 'void'
От: NeoCode  
Дата: 26.05.14 04:46
Оценка:
Здравствуйте, _NN_, Вы писали:

NC>>void и unit это разные вещи.

_NN>Боюсь люди получат тут разрыв шаблона если будет два пустых значения

Есть еще http://en.wikipedia.org/wiki/Bottom_type

_NN>А почему тогда нельзя такое же провести с void ?

_NN>Компилятор за нас спрячет детали и выбросит пустые аргументы сам.

Думаю я немного ошибся: http://en.wikipedia.org/wiki/Unit_type
unit — это "улучшенный void", и он же "0-tuple". Но все равно мне не нравится идея передавать в функцию, принимающую void, "результат" другой функции, возвращающей void.

В некоторых языках есть возможность возвращать несколько возвращаемых значений (кортеж). Т.е. возможно например такое
function foo() : int, float {return 10, 3.14;}
x,y = foo();

Если такое возможно, то захочется передавать возвращаемый кортеж вместо нескольких аргументов в другую функцию:
function bar(char c, int x, float f, string s) {}
bar('q',foo(),"hello");

кто-то скажет что это красиво, а я считаю что такое только запутает.

Еще хуже, возможность передачи void в void формально (по аналогии) открывает возможность передачи void куда угодно помимо основного списка аргументов. Т.е. в функцию bar() можно вызвать так
bar(v(), 'q', v(), v(), 100, 1.23, v(), "hello", v(), v());
(где v() — функция, возвращающая void)
Re[5]: Тип 'void'
От: NeoCode  
Дата: 26.05.14 05:40
Оценка:
Здравствуйте, Don Reba, Вы писали:

DR>Тут в bar передаётся не (char*int*float*string), а (char*(int*float)*string) — это другой тип. Зачем их отождествлять?


Согласен. А например тип int эквивалентен типу int*void? или void*int*void? Или это все-же разные типы?
Re[6]: Тип 'void'
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 26.05.14 05:51
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>Согласен. А например тип int эквивалентен типу int*void? или void*int*void? Или это все-же разные типы?


Думаю, все разные. Иначе, как ты уже показал, получается путаница.
Ce n'est que pour vous dire ce que je vous dis.
Re[7]: Тип 'void'
От: NeoCode  
Дата: 26.05.14 05:57
Оценка:
Здравствуйте, Don Reba, Вы писали:

NC>>Согласен. А например тип int эквивалентен типу int*void? или void*int*void? Или это все-же разные типы?

DR>Думаю, все разные. Иначе, как ты уже показал, получается путаница.

Путаница в том, что если void — это отсутствие параметра, а мы туда все-же передаем "возврат" другой функции, возвращающей void,
то что мешает нам передать void в функцию вместо второго, третьего и т.д. отсутствующих параметров?
function v() {}
function foo() {}
function bar(int) {}

foo();    // OK
foo(v()); // OK?

bar(100); // OK
bar(100, v(), v(), v()); // OK???
Re[2]: Тип 'void'
От: _NN_  
Дата: 26.05.14 07:20
Оценка:
Здравствуйте, hi_octane, Вы писали:

_>Пока не рассматриваем случай Nullable<void>/void? который уже bool получается, и при этом попадает под требование работы с void как с обычными типами

А в чем проблема ? Это ведь не единичный случай для странного кода

_>Очевидно что a,b,c,d реально не используются — будет удобно, если любое значение которое не используется, будет приводиться к void и не компостировать мозг своим типом.



_>Основное удобство void как типа в Generic'ах. А то в C# эти Action<T> и Func<T> уже достали.

Функциональный тип всех бы спас ( void -> void ) .

_>Как пример удобства — допустим у нас есть готовый Dictionary<TKey, TValue> лёгким движением руки через

_>var hashSet = new Dictionary<int, void>(); эта коллекция превращается в Set. При этом метод hashSet.Add(key : TKey, value : TValue), внезапно начинает компилироваться с одним аргументом hashSet.Add(5), так как void в недостающие места компилятор и сам подсунуть может. Красота

Согласен.
Скажем '()' это литерал void.

void F() {}

F(); // OK
F( () ); // OK
F( () , () );// OK

void G() {}
F( G(), G(), G() );


По сути ничем это не отличается от анонимного блока возвращающего void, только без дополнительных скобок: F( { G(), G(), G() } );

_>Как элемент мозгового штурма, а что если в языке object будет наследником от void?

А какая разница кто кого наследует.
Это детали реализации, главное чтобы компилятор справился.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: Тип 'void'
От: _NN_  
Дата: 26.05.14 07:27
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>Здравствуйте, _NN_, Вы писали:


NC>>>void и unit это разные вещи.

_NN>>Боюсь люди получат тут разрыв шаблона если будет два пустых значения

NC>Есть еще http://en.wikipedia.org/wiki/Bottom_type

Я в курсе

NC>кто-то скажет что это красиво, а я считаю что такое только запутает.


Автораскрытие кортежей это плохо.
Зато явно очень удобно (см. Python )

NC>Еще хуже, возможность передачи void в void формально (по аналогии) открывает возможность передачи void куда угодно помимо основного списка аргументов. Т.е. в функцию bar() можно вызвать так

NC>
bar(v(), 'q', v(), v(), 100, 1.23, v(), "hello", v(), v());
(где v() — функция, возвращающая void)


А чем тут плохо ?
Возьмем язык с анонимными блоками , кстати в C# скоро обещают вроде как.
Осталось только поддерживать void.
F(a : int) : void {}
G() : void {}

F({ Do1(); Do2(); 1 }); // <--> Do1(); Do2(); F(1);
G({ Do1(); Do2(); () }); // <--> Do1(); Do2(); F();
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: Тип 'void'
От: NeoCode  
Дата: 26.05.14 07:40
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>По-моему, вы слишком много думаете о конкретных типах. Ценность "единого void" — в обобщённом коде.

S>Вот простой пример: мы хотим сделать тип "типизированный словарь", который хранит отображение ключ->значение.
S>При этом подразумевается уникальность ключа и бла-бла-бла.
S>Если у нас есть полноценная поддержка типа void, то тип "множество значений" получается как тривиальный частный случай: Set<TKey> == Dictionary<TKey, void>. А если нет (как, скажем, в дотнете), то нам нужно городить два совершенно несвязанных интерфейса для ISet<TKey> и IDictionary<TKey, TValue>.
S>Опять же, всякие ФВП приходится писать дважды — для функций, возвращающих значение, и для невозвращающих значение.

Я не против void как полноценного типа, только за. Просто хочется понять, как будут выглядеть многочисленные частные случаи и к чему это приведет.
В частности, допустим, функция объявлена например как
function foo(void, int, void);

(такое может получиться, например, из шаблонной функции при подстановке void в параметры шаблона)
Должен ли компилятор "сворачивать" ее к виду "foo(int)"?

Если должен (а я так понимаю из примера с Map и Set, ради этого все и делается), то имеем ли мы право вызвать ее в "оригинальном" виде
foo(v(), 100, v());

или только в "сокращенном"?
По идее, в оригинальном виде тоже можно (полноценный тип же). Но из этого следует возможность расширить еще еще дальше, т.е. втыкать void в любые функции? Или не следует?
Re[6]: Тип 'void'
От: _NN_  
Дата: 26.05.14 07:47
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>Я не против void как полноценного типа, только за. Просто хочется понять, как будут выглядеть многочисленные частные случаи и к чему это приведет.

NC>В частности, допустим, функция объявлена например как
NC>
function foo(void, int, void);

NC>(такое может получиться, например, из шаблонной функции при подстановке void в параметры шаблона)
NC>Должен ли компилятор "сворачивать" ее к виду "foo(int)"?
Я считаю, что должен.

NC>Если должен (а я так понимаю из примера с Map и Set, ради этого все и делается), то имеем ли мы право вызвать ее в "оригинальном" виде

NC>
foo(v(), 100, v());

NC>или только в "сокращенном"?
NC>По идее, в оригинальном виде тоже можно (полноценный тип же). Но из этого следует возможность расширить еще еще дальше, т.е. втыкать void в любые функции? Или не следует?
Не вижу проблемы втыкать void.
Более того его и сейчас можно воткнуть вполне легально:
#include <iostream>
using namespace std;

void g() {cout<<"g";}
void f(int) {cout<<"f";}

int main()
{
    f( (g(), 1) );

    return 0;
}

gf
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[7]: Тип 'void'
От: NeoCode  
Дата: 26.05.14 08:02
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Не вижу проблемы втыкать void.

_NN>Более того его и сейчас можно воткнуть вполне легально:
_NN>
_NN>#include <iostream>
_NN>using namespace std;

_NN>void g() {cout<<"g";}
_NN>void f(int) {cout<<"f";}

_NN>int main()
_NN>{
_NN>    f( (g(), 1) );

_NN>    return 0;
_NN>}
_NN>

_NN>
_NN>gf
_NN>


В данном случае синтаксически явно (скобками) выделен аргумент, внутри которого может быть что угодно. В языках, в которых блоки кода могут возвращать значения, можно воткнуть в аргмент целый кусок кода с циклами, условыми переходами и вероятно даже объявлениями классов. Против этого я ничего не имею.
В случае void становятся возможными вставки void просто в основной список аргументов, т.е. со стороны это выглядит именно как передача полноценных аргументов
f( g(), 1 );
f( g(), g(), 1, g(), g() );
// и т.д.

Более того, такое невозможно сделать ни с одним другим типом. ИМХО, это вносит путаницу и именно это мне не нравится.
Re[6]: Тип 'void'
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.05.14 08:34
Оценка:
Здравствуйте, NeoCode, Вы писали:
NC>Я не против void как полноценного типа, только за. Просто хочется понять, как будут выглядеть многочисленные частные случаи и к чему это приведет.
NC>В частности, допустим, функция объявлена например как
NC>
function foo(void, int, void);

NC>(такое может получиться, например, из шаблонной функции при подстановке void в параметры шаблона)
NC>Должен ли компилятор "сворачивать" ее к виду "foo(int)"?
Желательно — это специальный сахар.

NC>Если должен (а я так понимаю из примера с Map и Set, ради этого все и делается), то имеем ли мы право вызвать ее в "оригинальном" виде

NC>
foo(v(), 100, v());

Да. После раскрытия шаблона у нас будет получаться примерно такой же код, поэтому я не вижу причин заставлять его не работать.
NC>По идее, в оригинальном виде тоже можно (полноценный тип же). Но из этого следует возможность расширить еще еще дальше, т.е. втыкать void в любые функции? Или не следует?
Нет, не следует. Попытки скормить default(void) в неожиданные места должны приводить к ошибкам типизации.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Тип 'void'
От: C.A.B LinkedIn
Дата: 26.05.14 08:35
Оценка:
Здравствуйте, hi_octane, Вы писали:
_>Как элемент мозгового штурма, а что если в языке object будет наследником от void?
Тогда void не будет безопасно приводится ни к какому другому типу, что сведёт на нет профит от него.
И это не логично, получается что переменные типа void могут хранить ссылку на любой объект, т.е. не являться "void".
Между тем,что я думаю,тем,что я хочу сказать,тем,что я,как мне кажется,говорю,и тем,что вы хотите услышать,тем,что как вам кажется,вы слышите,тем,что вы понимаете,стоит десять вариантов возникновения непонимания.Но всё-таки давайте попробуем...(Э.Уэллс)
Re[8]: Тип 'void'
От: _NN_  
Дата: 26.05.14 08:44
Оценка:
Здравствуйте, NeoCode, Вы писали:

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

NC>В случае void становятся возможными вставки void просто в основной список аргументов, т.е. со стороны это выглядит именно как передача полноценных аргументов
NC>
f( g(), 1 );
NC>f( g(), g(), 1, g(), g() );
NC>// и т.д.
NC>

NC>Более того, такое невозможно сделать ни с одним другим типом. ИМХО, это вносит путаницу и именно это мне не нравится.

Ну сейчас невозможно вызвать функцию с передачей void значение. Такое невозможно сделать с другим типом
В принципе такое нужно только в обобщенном коде.
Возможно в обычном действительно вносит лишнюю путаницу.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[7]: Тип 'void'
От: NeoCode  
Дата: 26.05.14 09:33
Оценка:
Здравствуйте, Sinclair, Вы писали:

NC>>По идее, в оригинальном виде тоже можно (полноценный тип же). Но из этого следует возможность расширить еще еще дальше, т.е. втыкать void в любые функции? Или не следует?

S>Нет, не следует. Попытки скормить default(void) в неожиданные места должны приводить к ошибкам типизации.

То есть получается следующее:
1. если функция объявлена (тем или иным способом — явно или в результате раскрытия обобщенного кода) например как foo(void,int,void,void), то ее можно "сокращать" ко всем вариантам, получаемым путем выкидывания одного или нескольких void. Все эти варианты будут эквивалентны. Но только сокращать — вставлять void-значения в произвольные места в списке аргументов функции (туда где их не было в прототипе) нельзя.

Сразу вопрос — а должны ли быть эквивалентны варианты foo(void,int) и foo(int)? ведь void у нас теперь полноценный тип.

2. Функция, объявленная как foo(), эквивалентна функции foo(void), т.е. отсутствие аргументов вообще эквивалентно одному аргументу void. Это исключение вводится для того, чтобы можно было писать foo(bar()); для void.

А кому-то захочется передать foo(bar(), bar()); Ведь чем один void-аргумент лучше двух или трех?

Опять некрасивое противоречие, приводящее в конечном итоге все к тому же — к возможности пихать void-значнения в произвольные места списков аргументов функций при их вызове.
Re[8]: Тип 'void'
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 26.05.14 09:47
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>То есть получается следующее:

NC>1. если функция объявлена (тем или иным способом — явно или в результате раскрытия обобщенного кода) например как foo(void,int,void,void), то ее можно "сокращать" ко всем вариантам, получаемым путем выкидывания одного или нескольких void. Все эти варианты будут эквивалентны. Но только сокращать — вставлять void-значения в произвольные места в списке аргументов функции (туда где их не было в прототипе) нельзя.

NC>Сразу вопрос — а должны ли быть эквивалентны варианты foo(void,int) и foo(int)? ведь void у нас теперь полноценный тип.


Похожая логика уже есть для параметров со значениями по умолчанию: выкидывать можно, вставлять лишние нет; foo(int a, bool b = false) не эквивалентен foo(int a); даны правила для разрешения потенциальных неоднозначностей.
Ce n'est que pour vous dire ce que je vous dis.
Re[9]: Тип 'void'
От: NeoCode  
Дата: 26.05.14 11:08
Оценка:
Здравствуйте, Don Reba, Вы писали:

DR>Похожая логика уже есть для параметров со значениями по умолчанию: выкидывать можно, вставлять лишние нет; foo(int a, bool b = false) не эквивалентен foo(int a); даны правила для разрешения потенциальных неоднозначностей.


Соглсен. А с
void v();
void foo();
foo(v(), v(), v())

что делать?
Re: Тип 'void'
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.05.14 12:35
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Насколько логично относиться к 'void' или 'Unit' как к обычному типу ?

_NN>Скажем, логично ли требовать чтобы код с обычными типами работал и с void ?

Разумеется, логично.

_NN>А с void ?

_NN>
_NN>function f(a : void) {..}
_NN>function g(b : void) {..}
_NN>function h(c : void, d : void) {..}

_NN>var x = f();
_NN>f(g()); // OK ?
_NN>f(x); // OK ?
_NN>h(f(), g()); // OK ?
_NN>


если void это нормальный тип, то нет никакой проблемы — параметр тоже может быть void

в обычном коде это не нужно, а вот в дженериках очень даже нужно
Re[10]: Тип 'void'
От: Don Reba Канада https://stackoverflow.com/users/49329/don-reba
Дата: 26.05.14 15:24
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>Соглсен. А с

NC>
NC>void v();
NC>void foo();
NC>foo(v(), v(), v())

NC>что делать?

Если разрешить опускать void, но не вставлять лишние получается где-то так:

void v();
void foo0(); void foo1(void); void fooT<T>(T);
foo0(v());    // запретить!
foo1(v());    // OK
foo1();       // OK
fooT(v());    // OK
fooT<void>(); // OK


А ещё, мне не нравится потенциальная возможность параметризировать войдом при опущенном параметре:

fooT();       // запретить!
Ce n'est que pour vous dire ce que je vous dis.
Re[2]: Тип 'void'
От: Кодт Россия  
Дата: 26.05.14 16:32
Оценка:
Здравствуйте, deniok, Вы писали:

D>В языках с алгебраическими типами данных Unit — обычный тип, в котором имеется ровно одно значение.


На си то же самое можно сделать
struct SVoid {};


Тут, скорее проблема "безэлементный кортеж — это что?" и "одноэлементный кортеж — это что?"
В питоне, например, любой кортеж является последовательностью, и чтобы отличить кортеж от элемента, изобретён специальный синтаксис конструирования
n  = None # аналог void / unit
x  = 1
z  = 0

# кортежи
ns = ()
xs = (1,)
zs = (0,)
ys = (0,0) # сова? сова бьян!

print bool(n) # false - пустой тип
print bool(x) # true - ненулевое значение
print bool(z) # false - нулевое значение

print bool(ns) # false - пустой кортеж
print bool(xs) # true - непустой кортеж
print bool(zs) # true - непустой кортеж, хотя и из нулей
Перекуём баги на фичи!
Re[8]: Тип 'void'
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.05.14 17:26
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>2. Функция, объявленная как foo(), эквивалентна функции foo(void), т.е. отсутствие аргументов вообще эквивалентно одному аргументу void.

Я думаю, это лишнее.
NC> Это исключение вводится для того, чтобы можно было писать foo(bar()); для void.
Зачем? У вас есть функция foo(). Она ничего не принимает. Зачем вы хотите передать в неё результат функции, даже если она ничего не возвращает?
Если у нас есть foo<T>(T a), и T bar<T>(), то композиция функций — дело приемлемое, и она должна работать, в том числе, и для T=void. Но совершенно непонятно, зачем разрешать "передавать" в foo() результат bar<T>(), ведь такой код будет работать только для одного типа параметра. А для него вместо foo(bar()) можно написать bar();foo().
NC>А кому-то захочется передать foo(bar(), bar()); Ведь чем один void-аргумент лучше двух или трех?
Надо делать не то, что "кому-то захочется", а то, что упрощает типовые сценарии.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: Тип 'void'
От: Кодт Россия  
Дата: 26.05.14 21:59
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Надо делать не то, что "кому-то захочется", а то, что упрощает типовые сценарии.


Я бы смягчил.

В конце концов, в С++ долго воевали за унификацию return smth и return void, в первую очередь, в шаблонах, — и к 2011 стандарту таки согласились, что можно, нужно и полезно.

То есть, сценарии есть, равно как и есть обходные решения. А делать надо, исходя из здорового умеренного консерватизма.
Потому что затащить в С++ систему типов, похожую на Хиндли-Милнера, например, — это было бы круто, но удовольствие очень дорогое.
Сделать void первоклассным типом — это удовольствие дешёвое, но возникают подводные грабли при обработке списка аргументов.

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

Допустим, к примеру, мы определим тип
namespace std {
  struct unit_t
  {
    unit_t() {}
    template<class T> unit_t(T const&) {} // любой тип можно привести к void, а значит, и к unit
  };
  static unit_t const unit;
}

std::unit_t foo(std::unit_t x, std::unit_t y, std::unit_t z) { return std::unit; }
std::unit_t v() { return std::unit; }

int main()
{
  foo( v(), v(), (v(),v(),v()) ); // третий операнд использует оператор запятую
}

Так, вроде бы понятно, как отличать последовательности от списка аргументов. Как в старом добром си, дополнительные скобки.
Недостаёт трёх вещей
— неявного приведения void к std::unit_t
— неявных return'ов в конце функций
— особой реализации оператора запятой, т.к. пользователь может определить свой оператор, который захавает unit_t, — но захавать чистый void не получится, — все operator,(void,T) и operator,(T,void) являются встроенными, — то же самое надо (?) и для unit_t

Это один путь.
Другой путь — не делать новый тип, а сразу принять void как первоклассный (т.е. внутренне реализовать его так же, как std::unit_t).
Тогда у нас встаёт проблема legacy — старый синтаксис
some foo(); // нуль-арная
some foo(void); // нуль-арная или, по-новому, унарная?

Волюнтаристский подход состоит в том, чтобы запретить старый стиль и трактовать всё сразу по-новому.
Резать-хвост-по-частям — в том, чтобы такие унарные функции домысливать до дефолтных параметров
some foo(); // имея в виду some foo(void _ = void());

foo();
foo( void() );
foo( bar ); // приводя значение bar к void
Перекуём баги на фичи!
Re[9]: Тип 'void'
От: Klapaucius  
Дата: 27.05.14 10:58
Оценка:
Здравствуйте, Sinclair, Вы писали:

NC>>2. Функция, объявленная как foo(), эквивалентна функции foo(void), т.е. отсутствие аргументов вообще эквивалентно одному аргументу void.

S>Я думаю, это лишнее.

А чем тут не подходит ваш же собственный аргумент в пользу возвращения void

Опять же, всякие ФВП приходится писать дважды — для функций, возвращающих значение, и для невозвращающих значение.

просто исправленный на "всякие ФВП приходится писать дважды — для функций, принимающих значение, и для непринимающих значение"?
Да тут дело даже не в том, что их приходится писать дважды, но и некий обобщенный код не будет рассчитан на такие случаи, и если вдруг понадобится в такой обобщенный код передать функцию, которая не принимает ничего — придется самому вводить тип Unit с одним значением и оборачивать "непринимающие" функции.
По крайней мере в подавляющим большинстве ФЯ именно так и сделано, () — это значение тина unit, единственное населяющее этот тип (не считая _|_ в ленивых языках) — это проверенное временем решение.
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[10]: Тип 'void'
От: Sinclair Россия https://github.com/evilguest/
Дата: 28.05.14 03:49
Оценка:
Здравствуйте, Klapaucius, Вы писали:


K>А чем тут не подходит ваш же собственный аргумент в пользу возвращения void

K>

K>Опять же, всякие ФВП приходится писать дважды — для функций, возвращающих значение, и для невозвращающих значение.

K>просто исправленный на "всякие ФВП приходится писать дважды — для функций, принимающих значение, и для непринимающих значение"?
Тогда получается "...приходится писать бесконечное количество раз — для функций, принимающих 0 значений, 1 значение, 2 значения, и т.п."
А если ФВП способна работать с функцией, принимающей N аргументов, то она отлично справится и с N=0.
Если, конечно, логика ФВП этому не противоречит — например, каррировать функцию без аргументов уже не получится.

K>Да тут дело даже не в том, что их приходится писать дважды, но и некий обобщенный код не будет рассчитан на такие случаи, и если вдруг понадобится в такой обобщенный код передать функцию, которая не принимает ничего — придется самому вводить тип Unit с одним значением и оборачивать "непринимающие" функции.

K>По крайней мере в подавляющим большинстве ФЯ именно так и сделано, () — это значение тина unit, единственное населяющее этот тип (не считая _|_ в ленивых языках) — это проверенное временем решение.
Тогда проще отказаться от функций, не принимающих значение.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[11]: Тип 'void'
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 28.05.14 08:24
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Если, конечно, логика ФВП этому не противоречит — например, каррировать функцию без аргументов уже не получится.

S>...
S>Тогда проще отказаться от функций, не принимающих значение.

Именно так и надо поступить. Тогда и с каррированием проблем не будет: f () — вызов, f — каррированная ф-я.
Re[5]: Тип 'void'
От: NeoCode  
Дата: 29.05.14 13:35
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Автораскрытие кортежей это плохо.

_NN>Зато явно очень удобно (см. Python )

Кстати, можно ссылку или пример из python с этим раскрытием кортежей?
Re[6]: Тип 'void'
От: _NN_  
Дата: 01.06.14 19:48
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>Кстати, можно ссылку или пример из python с этим раскрытием кортежей?


Пожалуйста:
def f(a, b, c): print("a = {}, b = {}, c = {}".format(a, b, c))

x = (1,2,3)

f(*x)


a = 1, b = 2, c = 3
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Тип 'void'
От: NeoCode  
Дата: 21.06.14 20:59
Оценка:
Здравствуйте, _NN_, Вы писали:

Систематизирую организацию кортежей в различных языках. И вот какой вопрос с void возник совершенно неожиданно.

1. Если функция возвращает значение, а оно не используется — это нормально и менять это (заставлять использовать плейсхолдер для ненужного возвращаемого значения) крайне не хочется. Просто неудобно.
func foo() int { return 10;}
foo(); // теряем возвращаемое значение
_ = foo(); // так правильнее, но писать каждый раз лень!


2. По аналогии получается, если функция возвращает два и более значения (кортеж), то мы обязаны разрешить терять эти значения — иначе нарушится логика языка. Именно такое поведение реализовано например в Go.
func bar() int, float { return 10, 1.23; }
i, f = bar(); // ok
i = bar(); // ok, теряем второе значение
bar(); // ok, теряем все


3. Присваивание — обычная операция, ничем не отличающаяся от остальных. И экстраполируя поведение множественного присваивания на остальные операции, неизбежно получаем правило, что множественные операции выполняются над минимальным кортежем, участвующим в операции.
// '@' - некоторая бинарная операция
x @ 1,2,3; // выполняется x @ 1, остальное выкидываем
x,y,z @ 1; // выполняется x @ 1, остальное выкидываем


4. Поскольку void — это нуль-арный кортеж, то неизбежно получаем результат, что любые операции над void с точки зрения компилятора допустимы и просто игнорируются. Рассмотрим действия с переменной типа void:
_void_ = 1; // ok, ничего не происходит
x = _void_; // ok, ничего не происходит, значение x остается тем которое было до присваивания


5. Вообще говоря, из этого свойства следует очень интересное следствие: любые фрагменты выражений с участием переменной void следует игнорировать, а не ругаться на ошибки компиляции:
 x = y * (z + _void_); // x = y*z

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

Собственно вот. К чему приводит лень — попытка облегчить жизнь введением исключения из правила привела в конце концов к усложнению этой же жизни в самом неожиданном месте
Re[2]: Тип 'void'
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.06.14 13:34
Оценка:
Здравствуйте, hi_octane, Вы писали:

_>Как элемент мозгового штурма, а что если в языке object будет наследником от void?


Рак мозга будет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Тип 'void' - TypeScript
От: _NN_  
Дата: 10.08.14 13:33
Оценка:
В TypeScript на удивление как раз можно использовать void в параметрах обобщений:

interface DictionaryOrSet<K, V> {
  add(key : K, value : V) : void;
}

class Dictionary<K,V> implements DictionaryOrSet<K,V> {
  add(key : K, value : V) : void { }
}

class Set<T> implements DictionaryOrSet<T,void> {
  add(value : T) : void { }
}

var d = new Dictionary<number, string>();
d.add(1, "A");

var s = new Set<number>();
s.add(1);
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Тип 'void' - TypeScript
От: NeoCode  
Дата: 11.08.14 07:28
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>В TypeScript на удивление как раз можно использовать void в параметрах обобщений:


Интересно. А есть какие-то правила "свертки" кода, если вместо типа оказывается void?
Не знаю typescript, но например если там в каком-то выражении используется value, которое оказывается типа void — что происходит с выражением?
Re[2]: Тип 'void' - TypeScript
От: Qodomoc Россия  
Дата: 11.08.14 07:59
Оценка:
Возможно, это из-за того, что в javascript функция, которая ничего явно не возвращает, неявно вернет undefined.
Re[3]: Тип 'void' - TypeScript
От: _NN_  
Дата: 11.08.14 11:16
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>Здравствуйте, _NN_, Вы писали:


_NN>>В TypeScript на удивление как раз можно использовать void в параметрах обобщений:


NC>Интересно. А есть какие-то правила "свертки" кода, если вместо типа оказывается void?

В спецификации не нашел явного упоминания: http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf

3.2.4 The Void Type
The Void type, referenced by the void keyword, represents the absence of a value and is used as the return type of functions with no return value.
The only possible values for the Void type are null and undefined. The Void type is a subtype of the Any type and a supertype of the Null and Undefined types, but otherwise Void is unrelated to all other types.

NOTE: We might consider disallowing declaring variables of type Void as they serve no useful purpose. However, because Void is permitted as a type argument to a generic type or function it is not feasible to disallow Void properties or parameters.


Не знаю как должно быть, но вот так можно:
interface A<T> {
 f(x:number,a: T);
}

<A<void>>(null).f(1); // <> это приведение типа, т.е. в стиле C: ((A<void>)(null)).f(1)

А вот так уже нельзя
var a = <A<void>>(null);
a.f(1);


Ну и аналогично так правильно
interface A<T> {
 f(x:number,a: T);
}

class B implements A<void> {
 f(x:number) {}
}


А явно 'void' указывать нет:
interface A<T> {
 f(x:number,a: T);
}

class B implements A<void> {
 f(x:number, a:void) {}
}


new B().f(1); // Error
// Надо так
// new B().f(1, undefined);


NC>Не знаю typescript, но например если там в каком-то выражении используется value, которое оказывается типа void — что происходит с выражением?

Если аргумент сделать типом 'void' явно то будет явное использование.
И в этом случае нужно будет явно передать значение undefined или null.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: Тип 'void' - TypeScript
От: _NN_  
Дата: 11.08.14 12:29
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN><A<void>>(null).f(1); // <> это приведение типа, т.е. в стиле C: ((A<void>)(null)).f(1)

_NN>[/java]
_NN>А вот так уже нельзя
_NN>
_NN>var a = <A<void>>(null);
_NN>a.f(1);
_NN>


Я тут не прав.
<A<void>>(null).f(1) == (<A<void>>)((null).f(1))

А вот так действительно нельзя как и в случае переменной.
(<A<void>>(null)).f(1)
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Тип 'void'
От: Mamut Швеция http://dmitriid.com
Дата: 12.08.14 10:38
Оценка:
_NN>Насколько логично относиться к 'void' или 'Unit' как к обычному типу ?

Имхо, void вообще не имеет право на существование.

The void type, in several programming languages derived from C and Algol68, is the type for the result of a function that returns normally, but does not provide a result value to its caller.


То есть понятно, что void появился, как костыль. В случае, если everything is an expression, и все возвращает значение, то void не нужен. От слова совсем


dmitriid.comGitHubLinkedIn
Re[2]: Тип 'void'
От: _NN_  
Дата: 18.08.14 06:46
Оценка:
Здравствуйте, Mamut, Вы писали:


M>Имхо, void вообще не имеет право на существование.

M>То есть понятно, что void появился, как костыль. В случае, если everything is an expression, и все возвращает значение, то void не нужен. От слова совсем

Ну будет называться Unit, а не void. Разница то
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Тип 'void'
От: NeoCode  
Дата: 18.08.14 07:48
Оценка:
Здравствуйте, Mamut, Вы писали:

M>Имхо, void вообще не имеет право на существование.


void это не тип, это "псевдотип". В действительности через void обозначается пустой список аргументов или вовзращаемых значений, 0-арный кортеж. То есть если есть функция foo(int,float) — у нее список аргументов "int,float" это тип? Нет, это не тип, это нечто более абстрактное — это кортеж, список сущностей времени компиляции (каждая из которых уже является типом). void точно также не тип, а список, только пустой.

Идея привести void к типу в общем полезная, но нужно помнить что это именно "псевдотип" и учитывать это, не требуя от void полностью вписываться в систему типов — тогда можно построить преемлемую модель использования void и аккуратно обойти все проблемы с ним.
Re[7]: Тип 'void'
От: Aleх  
Дата: 10.09.14 21:49
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Здравствуйте, NeoCode, Вы писали:


NC>>
function foo(void, int, void);

NC>>(такое может получиться, например, из шаблонной функции при подстановке void в параметры шаблона)
NC>>Должен ли компилятор "сворачивать" ее к виду "foo(int)"?

DM>Мой ответ: нет, ни в коем случае. От этого опять куча проблем и граблей.


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

DM>А foo(void, int, void) принимает тупл из трех элементов, ни больше ни меньше.

Возникает следующий вопрос.
Считать ли выражения ((a, b), c) и (a, b, c) эквивалентными?
1. Если да, то получается правило такое, что мы можем вставить содержимое вложенных кортежей в текущий. Пусть a имеет тип void, то есть a = (). Тогда получается, что ((a, b), c) эквивалентно ((), b, c), а это эквивалентно (b, c) (в первом преобразовании первый элемент внешнего кортежа преобразовался в два элемента из вложенного кортежа, а во втором преобразовании первый элемент внешнего кортежа преобразовался в ноль элементов). В этой схеме полезным свойством является то, что скобки не принимают непосредственное участие в задании кортежа. Вместо этого кортеж определяется запятыми, а скобки играют роль группировки операторов как в арифметических выражениях.

2. Если считать эти выражения различными, возникает проблема с кортежем единичного размера. Будет ли ((a), c) эквивалентно (a, c)? Считаются ли ((a)), (a) и a эквивалентными? Остается два варианта — либо считать эти выражения различными, либо рассматривать кортеж из одного элемента специальным образом. Считать их различными кажется дико неудобно, а иметь специальные правила для единичного кортежа — костыль, который тоже вызовет кучу проблем и граблей.

В итоге нужно определиться, какое из решений вызывает меньше проблем и граблей. Я думаю, всё-таки лучше сворачивать пустые кортежи типа void, чем иметь специальные правила для кортежей из одного элемента.
Отредактировано 10.09.2014 21:52 Aleх . Предыдущая версия .
Re[8]: Тип 'void'
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 11.09.14 04:51
Оценка:
Здравствуйте, Aleх, Вы писали:

A>Возникает следующий вопрос.

A>Считать ли выражения ((a, b), c) и (a, b, c) эквивалентными?

Ни в коем случае. В некоторых языках, правда, эквивалентными считаются (a, (b, c)) и (a, b, c), что довольно удобно.

A>1. Если да, то получается правило такое, что мы можем вставить содержимое вложенных кортежей в текущий. Пусть a имеет тип void, то есть a = (). Тогда получается, что ((a, b), c) эквивалентно ((), b, c), а это эквивалентно (b, c) (в первом преобразовании первый элемент внешнего кортежа преобразовался в два элемента из вложенного кортежа, а во втором преобразовании первый элемент внешнего кортежа преобразовался в ноль элементов).


Это безобразие, которое вызовет массу проблем. Проблем не будет, если туплы считать размером от 2. (а) и () — не туплы. (а) это просто а. () — это значение своего типа () а.к.а unit.

A>2. Если считать эти выражения различными, возникает проблема с кортежем единичного размера. Будет ли ((a), c) эквивалентно (a, c)? Считаются ли ((a)), (a) и a эквивалентными? Остается два варианта — либо считать эти выражения различными, либо рассматривать кортеж из одного элемента специальным образом. Считать их различными кажется дико неудобно, а иметь специальные правила для единичного кортежа — костыль, который тоже вызовет кучу проблем и граблей.


Решение простое: не иметь кортежей единичного (и нулевого) размеров. Не так уж сложно, и никаких граблей.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.