Тип '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'
От: 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'
От: 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: Тип '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: Тип '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[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[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[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[8]: Тип 'void'
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 26.05.14 06:34
Оценка: +2
Здравствуйте, NeoCode, Вы писали:

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


А вот не надо его определять как отсутствие параметра. От этого только одни проблемы и неудобства.
Вспомните математику: функция есть отображение из чего-то в чего-то, не бывает в принципе функций, которые ничего не принимают или ничего не возвращают. Когда вместо void используется unit, он же (), его можно и пустым туплом считать, все получается логично и удобно. А иначе возникает масса специальных случаев, мешающих писать универсальный/обобщенный код.
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[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".
Между тем,что я думаю,тем,что я хочу сказать,тем,что я,как мне кажется,говорю,и тем,что вы хотите услышать,тем,что как вам кажется,вы слышите,тем,что вы понимаете,стоит десять вариантов возникновения непонимания.Но всё-таки давайте попробуем...(Э.Уэллс)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.