Re[3]: Баг №3
От: Gaperton http://gaperton.livejournal.com
Дата: 04.07.05 11:42
Оценка:
Здравствуйте, Gaperton, Вы писали:

неверный тип второго аргумента:
void for( open void i_init(); bool i_cond(); void i_iterate() ) arg( void i_body() )
{
}


Вот так теперь можно писать:
...
void myFun()
{
   std::set< int > mySet;
   void someFunc() { int x = 1; }
   void body() { mySet.insert( x ) }
   for( someFunc; x != n; { x++; doSomethingStupid( x, mySet ) } ) body;
}
...

Нравиццо?
Re[2]: Примитивные конструкции языка
От: Трурль  
Дата: 04.07.05 13:05
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>4) Самое сложное. Надо добавить возможность функции брать в качестве аргумента выражение (функцию) после скобок.

Может быть здесь пригодилась бы предлагаемая Страуструпом перегрузка пробела?
Re[4]: Баг №3
От: WolfHound  
Дата: 04.07.05 13:26
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Вот так теперь можно писать:

G>
G>...
G>void myFun()
G>{
G>   std::set< int > mySet;
G>   void someFunc() { int x = 1; }
G>   void body() { mySet.insert( x ) }
G>   for( someFunc; x != n; { x++; doSomethingStupid( x, mySet ) } ) body;
G>}
G>...
G>

G>Нравиццо?
Круто. А теперь придумай возможность добавлять ключавые слова типа break и continue.
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: Баг #4
От: Gaperton http://gaperton.livejournal.com
Дата: 04.07.05 13:35
Оценка: :)
Здравствуйте, Трурль, Вы писали:

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


G>>4) Самое сложное. Надо добавить возможность функции брать в качестве аргумента выражение (функцию) после скобок.

Т>Может быть здесь пригодилась бы предлагаемая Страуструпом перегрузка пробела?

Не, по моему и так неплохо получилось. Только осталась еще одна одна маленькая проблема — с break, continue и return внутри безымянных {} блоков, а так — все хорошо.

Ну, это в целом тоже просто. Вводим еще одно правило — употребление имени функции типа void() при условии, что она не является, аргументом функции, эквивалентно вызову этой функции.

Теперь можно сделать так:

enum __for{ __for_continue, __for_break };
void continue() { throw __for_continue; }
void break() { throw __for_break; }


Эксцепшены будем ловить внутри for. Остался return — это жесткач. Вводим дополнительное правило — return, употребленный внутри безымянной функции void() приводит не только к выходу из нее, но к выходу из первой функции по стеку, не имеющей в определении модификатора passthrough (или defmacro - привет Lisp-ерам ). На функцию for вешаем модификатор passthrough, остальные функции по умолчанию его не имеют. Таким образом, у нас return будет работать корректно, как и раньше.

Интересная задачка из серии занимательный С++ , не находишь?
Re[5]: Баг №3
От: Gaperton http://gaperton.livejournal.com
Дата: 04.07.05 13:36
Оценка:
Здравствуйте, WolfHound, Вы писали:
WH>Круто. А теперь придумай возможность добавлять ключавые слова типа break и continue.
Уже
http://www.rsdn.ru/Forum/Message.aspx?mid=1254822&amp;only=1
Автор: Gaperton
Дата: 04.07.05
Re[4]: Баг #4
От: Трурль  
Дата: 04.07.05 14:15
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Эксцепшены будем ловить внутри for. Остался return — это жесткач. Вводим дополнительное правило — return, употребленный внутри безымянной функции void() приводит не только к выходу из нее, но к выходу из первой функции по стеку, не имеющей в определении модификатора passthrough (или defmacro - привет Lisp-ерам ). На функцию for вешаем модификатор passthrough, остальные функции по умолчанию его не имеют. Таким образом, у нас return будет работать корректно, как и раньше.


Мне, пожалуй, парочку!

G>Интересная задачка из серии занимательный С++ , не находишь?

Re[5]: Баг #4
От: Gaperton http://gaperton.livejournal.com
Дата: 04.07.05 14:25
Оценка:
Здравствуйте, Трурль, Вы писали:

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


G>>Эксцепшены будем ловить внутри for. Остался return — это жесткач. Вводим дополнительное правило — return, употребленный внутри безымянной функции void() приводит не только к выходу из нее, но к выходу из первой функции по стеку, не имеющей в определении модификатора passthrough (или defmacro - привет Lisp-ерам ). На функцию for вешаем модификатор passthrough, остальные функции по умолчанию его не имеют. Таким образом, у нас return будет работать корректно, как и раньше.


Т>Мне, пожалуй, парочку!


G>>Интересная задачка из серии занимательный С++ , не находишь?

Т>

Думаете это все? Да это только начало. Домашнее задание: расширить С++ до такой степени, штобы в терминах языка можно было бы определить конструкцию switch . И пусть живые завидую мертвым.
Re: Примитивные конструкции языка
От: DJ KARIES Россия  
Дата: 04.07.05 14:58
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Влад, это не просчет, это разница в подходе. Я, например, последнее время "болею" идеей, как бы можно было бы ввести в язык такую "фичу", чтоб прямо в терминах языка можно было бы for и while прозрачно выразить, оставив в языке только if и goto. Это, собственно, не для for и while нужно, а для того, чтоб алгоритмы, подобные тому, что в STL, были бы в языке first class citizens. А в C#, напротив, foreach в язык "воткнули". Вот такая вот разница.


У меня в forth-компилере "ref" не только for и while, но и + и — и прочие "stdcall" и "uses" написаны на этом же языке.

http://giref.forthworks.com

forth
: wsparse 32 parse ;
: lnparse 10 parse ;
macro
: f: wsparse find compile ;
: m: wsparse mfind compile ;
: ['] wsparse find m: literal ;
: >r $ad50 2, ;
: r> $8904ee83 , $5806 2, ;
: dup $8904ee83 , $06 1, ;
: drop $ad 1, ;
: swap $0687 2, ;
: nip $04c683 3, ;
: and $0623 2, m: nip ;
: or $060b 2, m: nip ;
: xor $0633 2, m: nip ;
: >> $d3adc189 , $e8 1, ;
: << $d3adc189 , $e0 1, ;
: not -1 m: literal m: xor ;
: @ $008b 2, ;
: ! $89adc289 , $ad02 2, ;
: c@ m: @ $ff m: literal m: and ;
: c! $c289 2, m: drop $0288 2, m: drop ;
: + $ad0601 3, ;
: - $ad0629 3, ;
: * $26f7 2, m: nip ;
: negate -1 m: literal m: * ;
: / $99adc389 , $fbf7 2, ;
: mod m: / $d089 2, ;
: here h0 m: literal m: @ ;
: : create here -5 + h0 ! ;
forth
: dup dup ;
: drop drop ;
: execute >r ;
: swap swap ;
: rot >r swap r> swap ;
: -rot rot rot ;
: tuck swap : over swap dup -rot ;
: 2dup over over ;
: 2drop drop drop ;
: nip nip ;
: and and ;
: or or ;
: xor xor ;
: >> >> ;
: << << ;
: not not ;
: @ @ ;
: ! ! ;
: c@ c@ ;
: c! c! ;
: + + ;
: * * ;
: negate negate ;
: - - ;
: / / ;
: mod mod ;
: here here ;
: ( ') parse drop drop ;
: | lnparse drop drop ;
: create: wsparse entry ;
: exit, $c3 1, ;
macro
: ( ') parse 2drop ;
: | lnparse 2drop ;
: 1+ $40 1, ;
: 1- $48 1, ;
: repeat here ;
: again compile ;
: next m: r> : until $48 1, $c009 2, $850f 2, here - 4 - , m: drop ;
: for here m: >r ; 
: r m: r> ['] dup compile m: >r ;
: if $c009 2, m: drop $840f 2, here 0 , ;
: (if) $063b 2, m: drop m: drop $0f 1, 1, here 0 , ;
: <>if $84 m: (if) ;
: =if $85 m: (if) ;
: <if $8e m: (if) ;
: >if $8d m: (if) ;
: ?if $063b 2, $820f 2, here 0 , ;
: then dup here swap - 4 - swap ! ;
: else $e9 1, here 0 , swap dup here swap - 4 - swap ! ;
: cell+ 4 m: literal m: + ;
: cell- 4 m: literal m: - ;
: cells 4 m: literal m: * ;
forth
: last> last @ ;
: >last last ! ;
: variable 0 : variable, create , ;
: literal, m: literal ;
: const create: literal, exit, ;
: hex 16 base ! ;
: decimal 10 base ! ;
: binary 2 base ! ;
: octal 8 base ! ;
: /mod over over / -rot mod ;
: pad here 1024 + ;
: allot here + h0 ! ;
: align 0 here 4 mod allot ;
: cell+ cell+ ;
: cell- cell- ;
: cells cells ;
: 2over >r >r 2dup r> -rot r> -rot ;
: 2swap rot >r rot r> ;
: ' wsparse find ;
: alias create: last @ cell+ ! ;
: fill swap repeat >r swap 2dup c! 1+ swap r> until 2drop ;
: 0; dup 0 =if r> 2drop ;; then ;
: >pad dup >r pad swap cmove pad r> ;
: zt-make dup >r here swap cmove here r> dup allot 0 1, 1+ ;
: zt-free negate allot ;
: cr 10 emit ;
: space 32 emit ;
: . (.) space ;
: u. (u.) space ;
: tab 9 emit ;
: del 8 emit ;
: clear 25 repeat cr until ;
: type dup 0 <>if repeat swap dup c@ emit 1+ swap until drop ;; then 2drop ;
: word.name dup 8 + dup 1+ swap c@ ;
: words last repeat @ 0; word.name type space again ;
: last.name last> word.name type ;

variable st0
: " '" parse >pad ;
: ." " type ;
: $, st0 @ 2dup m: literal m: literal 2dup + st0 ! swap cmove ;

macro
: s" " $, ;
forth
here st0 ! 4096 allot
: version# 0 0 8 ;
: .version s" ref " type
  version# rot . del '. emit swap . del '. emit . ;

.version
" (c)2005 Alexey Abramov :: djkaries at list.ru" type cr cr

forth
: @var wsparse find 5 + ;
macro
: mc: m: ['] ['] compile compile ;
: call $d0ff 2, ;
: to @var $a3 1, , m: drop ;
: addr @var $fc4689 3, $fc768d 3, $b8 1, , ;
: prior last @ >r last @ @ last ! wsparse find compile r> last ! ;

forth
| : cmove 3 - repeat >r 2dup swap @ swap ! 1+ >r 1+ r> r> until 2drop ;
: var 0 : var, create: literal, exit, ;
: vars: repeat var until ;
: to @var ! ;
: ns: create: last> literal, last> swap dup @ >last exit, ;
: ns; last> swap ! >last ;
: stack cells allot here var, ;

32 stack {@}
: { {@} cell- to {@} last> {@} ! ;
: } {@} @ >last {@} cell+ to {@} ;

{
  var nnn
  : {:}
    {@} @
    last>
    dup @ >last
    dup {@} @ swap !
    {@} !
    last
    repeat
      dup to nnn
      @
      2dup =if
        2drop {@} @ nnn !
        ;;
      then
    again
  ; {:}
}

: z" " zt-make drop ;

: as last> dup cell+ @ swap @ >last create last> cell+ ! ;
: late: here wsparse ] entry last @ cell+ ! ;

macro
: z" " zt-make drop ;

forth

: import
  create:
  GetProcAddress literal, m: call exit,
;

: stdcall
  create:
  dup if
    dup repeat
      m: >r
    until
  then
  drop
  GetProcAddress literal, m: call exit,
;

: stdcall*
  create:
  dup if
    dup repeat
      m: >r
    until
  then
  drop
  GetProcAddress literal, m: call m: drop exit,
;

: true -1 ;
: false 0 ;

" kernel32.dll" LoadLibraryAs KERNEL32

{
  KERNEL32 " GlobalAlloc" 2 stdcall GlobalAlloc
  KERNEL32 " GlobalFree" 1 stdcall GlobalFree
  : GMEM_FIXED 0 ;
  
  : getmem GMEM_FIXED swap GlobalAlloc ; {:}
  : freemem GlobalFree drop ; {:}
}

{
  KERNEL32 " CreateFileA" 7 stdcall CreateFile
  KERNEL32 " ReadFile" 5 stdcall ReadFile
  KERNEL32 " WriteFile" 5 stdcall WriteFile
  KERNEL32 " SetFilePointer" 4 stdcall SeekFile
  KERNEL32 " CloseHandle" 1 stdcall CloseHandle
  KERNEL32 " GetFileSize" 2 stdcall GetFileSize

  : CodeSize getmem h0 ! ; {:}

  : GENERIC_READ $80000000 ;
  : GENERIC_WRITE $40000000 ;

  : CREATE_NEW 1 ;
  : CREATE_ALWAYS 2 ;
  : OPEN_EXISTING 3 ;
  : OPEN_ALWAYS 4 ;
  : TRUNCATE_EXISTING 5 ;

  4 vars: SrcFile SrcFileSize SrcFileSizeReaded SrcFileData

  var uses_stored_voc
  var uses_voc
  var uses_level
  
  : used
    s" Used files: " type
    last> to uses_stored_voc
    uses_voc >last
    words cr
    uses_stored_voc >last
  ; {:}

  : terminate
    s" Program terminated." type cr
    bye
  ;

  : uses
    wsparse 2dup
    last> to uses_stored_voc
    uses_voc >last
    find ?if
      uses_stored_voc >last
      drop
      s" Warning: file '" type type s" ' is already used." type cr
      ;;
    then
    2dup entry
    uses_level 0 >if
      uses_level repeat
        32 emit
      until
    then
    s" uses " type type
    last> to uses_voc
    uses_stored_voc >last
    zt-make drop GENERIC_READ 0 0 OPEN_EXISTING 0 0 CreateFile to SrcFile

    SrcFile -1 =if
      cr s" File not found." type cr
      terminate
    then
    SrcFile 0 GetFileSize to SrcFileSize
    SrcFileSize 0 >if
      SrcFileSize getmem to SrcFileData
      SrcFile SrcFileData SrcFileSize addr SrcFileSizeReaded 0 ReadFile drop
    then
    SrcFile CloseHandle drop
    SrcFileSize 0 >if
      s"  -> " type SrcFileSize (u.) s"  bytes" type cr
      SrcFileData >r
      uses_level 1+ to uses_level
      SrcFileData SrcFileSize eval
      uses_level 1- to uses_level
      r> to SrcFileData
      SrcFileData freemem
    then
  ; {:}
}

uses main.f
ntr soft: www.dkdens.narod.ru :: ref: http://giref.forthworks.com
Re[24]: Примитивные конструкции языка
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 05.07.05 04:10
Оценка:
Здравствуйте, Denis2005, Вы писали:

>>> Так ли мне необходимо в языке ключевое слово mutable?


D>Внятных ответов пока небыло...


Так ведь, какой вопрос...
Вот, например, это можно почитать: http://www.rsdn.ru/article/cpp/QnAconst.xml
Автор(ы): Андрей Тарасевич
Дата: 30.10.2004


D>К вопросу добавляем необходимость ключевого слова volatile.


Ну, если ты на C++ с аппаратурой не работаешь, то вряд ли тебе потребуется volatile.
Тут был здоровенный флэйм про мультипоточность и volatile: volatile у переменной класса
Автор: Vet
Дата: 09.01.05
, так в нем проскакивали с ссылки на статьи с описанием причин появления volatile.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[6]: Баг #4
От: WFrag США  
Дата: 05.07.05 06:14
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>>>Эксцепшены будем ловить внутри for. Остался return — это жесткач. Вводим дополнительное правило — return, употребленный внутри безымянной функции void() приводит не только к выходу из нее, но к выходу из первой функции по стеку, не имеющей в определении модификатора passthrough (или defmacro - привет Lisp-ерам ). На функцию for вешаем модификатор passthrough, остальные функции по умолчанию его не имеют. Таким образом, у нас return будет работать корректно, как и раньше.


Т>>Мне, пожалуй, парочку!


G>>>Интересная задачка из серии занимательный С++ , не находишь?

Т>>

G>Думаете это все? Да это только начало. Домашнее задание: расширить С++ до такой степени, штобы в терминах языка можно было бы определить конструкцию switch . И пусть живые завидую мертвым.


Жестко. Так что там Гринспун про 10 правило говорил?
Re[24]: Примитивные конструкции языка
От: Павел Кузнецов  
Дата: 05.07.05 17:27
Оценка: +3 -1
AndrewVK,

>>> Невозможность модификации контейнера это не ограничение foreach, а ограничение итераторов стандартных контейнеров.


> ПК> Ну и что? Речь шла о том, что foreach подходит не везде. Это был один из примеров. Собственно, суть сводится к тому, что алгоритмов, связанных с обходом контейнера много, и foreach — один из них, далеко не всегда наиболее подходящий.


> Следи за губами — foreach это не алгоритм.


1) Не хами, и не хамим будешь... 2) Все зависит от выбранной терминологии.

> Алгоритм находится внутри итератора.


В моей терминологии внутри итератора находится описание порядка обхода, а foreach — алгоритм, сводящийся к перебору элементов в порядке, заданном итератором. Скажем, remove_if — тоже алгоритм, тоже работающий, основываясь на порядке обхода, заданном итератором, но, очевидно, отличающийся от for_each. Если тебе удобнее называть for_each, find, find_first_if, search, equal, remove_if, copy_if, replace_if, reverse и т.п. другим словом, замени "алгоритм" на него в моих предыдущих сообщениях и ниже.

> При наличии итератора, котjрый умеет определенным образом обрабатывать удаления? удалять внутри foreach можно.


Еще раз. Возможность удаления внутри foreach не является центральным аргументом, это просто пример, тем не менее остающийся валидным: для стандартных итераторов удаление работать не будет. Аргументом является наличие других, отличных от foreach, алгоритмов (в понимании, описанном выше), которые во многих случаях подходят намного лучше.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Примитивные конструкции языка
От: Павел Кузнецов  
Дата: 05.07.05 18:16
Оценка:
Gaperton,

> ПК> Я, например, последнее время "болею" идеей, как бы можно было бы ввести в язык такую "фичу", чтоб прямо в терминах языка можно было бы for и while прозрачно выразить, оставив в языке только if и goto. Это, собственно, не для for и while нужно, а для того, чтоб алгоритмы, подобные тому, что в STL, были бы в языке first class citizens. А в C#, напротив, foreach в язык "воткнули". Вот такая вот разница.


> Хе-хе . Если "язык" — это С++, то все довольно просто. Поехали: <...>


Да, что-то в более-менее похожем духе. Не обязательно в C++, но интересно. Сами for, while и т.п. переопределять, естественно, не предполагается. Хочется полноценной поддержки "алгоритмов", подобных STL algorithms. Естественно, для этого нужны лямбда-выражения и замыкания. На самом деле, далеко не обязательно, чтоб выглядело буквально как for и while, но хочется, чтоб количество лишних телодвижений у пользователя было минимальным. Также маячит идея, что (по мотивам некоторых функциональных языков) можно более удачно, чем шаблоны C++, ввести поддержку обобщенного программирования. В частности, в определенных случаях очень полезным может оказаться откладывание определения типа выражения, что в C++ не поддерживается. Например:
enum A { a };
enum B { b };

void foo(A);
void foo(B);

template< class T, class F >
void bar( T t, F f )
{
   f( t );
}

void g()
{
   bar( a, foo );
}

В C++ будет неоднозначность, т.к. выбрать тип foo в точке вызова bar не удастся. Хочется, чтоб можно было bar вызвать с "недовыведенным" типом. Есть устойчивое ощущение, что введение "прозрачных" замыканий лямбда-выражений зависит от возможности отложенного выведения типов.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[25]: Примитивные конструкции языка
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.07.05 19:26
Оценка: -2
Здравствуйте, Павел Кузнецов, Вы писали:

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

Паш, вникай в смысл, а резводи бодягу по каждому поводу.

АВК тебе сказал, что невозможность удаления элементов внутри оператора foreach языка C# обусловена не ограничениями этого оператора, а ограничениями итераторов стандартных контерйнеров.

Все! Точка! И не нужно разводить софистику на терминологическую тематику.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[26]: Примитивные конструкции языка
От: Павел Кузнецов  
Дата: 05.07.05 19:59
Оценка: +3
VladD2,

> Паш, вникай в смысл, а резводи бодягу по каждому поводу.


Чего и вам желаю...

> АВК тебе сказал, что невозможность удаления элементов внутри оператора foreach языка C# обусловена не ограничениями этого оператора, а ограничениями итераторов стандартных контерйнеров.


Вот я именно по этому поводу уже третий раз и отвечаю: это на смысл исходного сообщения
Автор: Павел Кузнецов
Дата: 30.06.05
, на которое отвечал AVK, вообще никак не влияет.

> Все! Точка! И не нужно разводить софистику на терминологическую тематику.


Вот о чем я и говорю в который раз: как называть foreach алгоритмом или валенком — не важно; важно, что таких "валенков" много, а поддержка в языке присутствует только для одного из них.

P.S. На этом я, пожалуй, закончу повторять одно и то же: кому захочется "вникнуть в смысл, а не развести бодягу по каждому поводу" — перечитает...
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[27]: Примитивные конструкции языка
От: VladD2 Российская Империя www.nemerle.org
Дата: 05.07.05 20:27
Оценка: -3
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Вот о чем я и говорю в который раз: как называть foreach алгоритмом или валенком — не важно;


Лучше называть его оператором. Будет всем спокойнее.

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


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

foreach — это еще фигня. Вот во многих современных языках встравивают такие фишки как list comprehension (конструктор списков). Если подходить к таким фичам с твоей позиции, то это просто таки надругательство над языком, так как в язык уже не просто встраивается паттерн. В его уже встраиваеются целые процедуры. Но вот работа со списками с их использованием становится почти декларативной.

В Руби, например, встроен такой "простенький" паттерн как continuations. Тоже надругательство.

Но вот что странно! Ты постоянно плюешся на подобные вещи в Шарпе и даже словом не объмолвишся о других языках. От чего такая изберательность? Давай обсудим Руби или Хаскель.

ПК>P.S. На этом я, пожалуй, закончу повторять одно и то же: кому захочется "вникнуть в смысл, а не развести бодягу по каждому поводу" — перечитает...


Ты это перед сном повторяй. Можно перед зеркалом. А то пожалуй кроме тебя все уже это запомнили. А тоы вот все пыташся докапаться до слова и уйти в другой лес.
... << RSDN@Home 1.1.4 beta 7 rev. 466>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Примитивные конструкции языка
От: alexeiz  
Дата: 06.07.05 03:50
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Gaperton,


>> ПК> Я, например, последнее время "болею" идеей, как бы можно было бы ввести в язык такую "фичу", чтоб прямо в терминах языка можно было бы for и while прозрачно выразить, оставив в языке только if и goto. Это, собственно, не для for и while нужно, а для того, чтоб алгоритмы, подобные тому, что в STL, были бы в языке first class citizens. А в C#, напротив, foreach в язык "воткнули". Вот такая вот разница.


>> Хе-хе . Если "язык" — это С++, то все довольно просто. Поехали: <...>


ПК>Да, что-то в более-менее похожем духе. Не обязательно в C++, но интересно. Сами for, while и т.п. переопределять, естественно, не предполагается. Хочется полноценной поддержки "алгоритмов", подобных STL algorithms. Естественно, для этого нужны лямбда-выражения и замыкания. На самом деле, далеко не обязательно, чтоб выглядело буквально как for и while, но хочется, чтоб количество лишних телодвижений у пользователя было минимальным.


Что мне не нравится в большинстве предложений, это то, что лямбда функции определяются внутри (). Поэтому получается, что {} скобки появляются внутри () скобок, и это очень неестественно для C-подобных языков. Так уже сделано в Java и C#. Выглядит это плохо, нечитабильно.

В то же время, для родных конструкций типа for блок {} идёт сразу за конструкцией, а не находится внутри неё. Поэтому, хочется, чтобы алгоритмы выглядели как можно ближе к родным конструкциям. Например:
vector<int> v;
for_each(v.begin, v.end())
{
   // lambda function
}

Здесь {} блок идёт сразу за вызовом функции вместо полагающейся точки с запятой.

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

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

Неплохо выглядет предложение использовать ; внутри параметров к функции. Например:
int b;
vector<int> v;
for_each(v.begin(), v.end(); void(int a))
{
    cout << a + b << endl;
}


Здесь void(int a) — это сигнатура функции, определённой сразу за for_each().

Далее следует вопрос, а как организовать замыкания? Наиболее логично, как мне кажется, представлять замыкания как функтор, который имеет operator() и содержит ссылки на локальный контекст.

В такой модели, код приведенный выше, преобразуется во что-то вроде следующего:
struct __closure {
    int & b_;
    __closure(int & b) : b_(b) {}
    void operator()(int a) {
        cout << a << b_ << endl;
    }
};

int b;
vector<int> v;
for_each(v.begin(), v.end(), __closure(b));
Re[25]: Примитивные конструкции языка
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 06.07.05 07:43
Оценка: -2
Здравствуйте, Павел Кузнецов, Вы писали:

>> Следи за губами — foreach это не алгоритм.


ПК>1) Не хами, и не хамим будешь...


Я не хамлю. Просто намекаю на то что игнорировать слова собеседника не очень конструктивно.

ПК>2) Все зависит от выбранной терминологии.


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

>> При наличии итератора, котjрый умеет определенным образом обрабатывать удаления? удалять внутри foreach можно.


ПК>Еще раз. Возможность удаления внутри foreach не является центральным аргументом, это просто пример, тем не менее остающийся валидным: для стандартных итераторов удаление работать не будет.


А казалось бы, при чему тут конструкция языка foreach?

ПК> Аргументом является наличие других, отличных от foreach, алгоритмов (в понимании, описанном выше), которые во многих случаях подходят намного лучше.


foreach это не алгоритм, это синтаксический сахар. Пока ты этого не поймешь, дальнейшее обсмуждение бессмысленно.
... << RSDN@Home 1.2.0 alpha rev. 508>>
AVK Blog
Re[3]: Примитивные конструкции языка
От: Gaperton http://gaperton.livejournal.com
Дата: 06.07.05 11:11
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Gaperton,


>> ПК> Я, например, последнее время "болею" идеей, как бы можно было бы ввести в язык такую "фичу", чтоб прямо в терминах языка можно было бы for и while прозрачно выразить, оставив в языке только if и goto. Это, собственно, не для for и while нужно, а для того, чтоб алгоритмы, подобные тому, что в STL, были бы в языке first class citizens. А в C#, напротив, foreach в язык "воткнули". Вот такая вот разница.


>> Хе-хе . Если "язык" — это С++, то все довольно просто. Поехали: <...>


ПК>Да, что-то в более-менее похожем духе. Не обязательно в C++, но интересно. Сами for, while и т.п. переопределять, естественно, не предполагается. Хочется полноценной поддержки "алгоритмов", подобных STL algorithms. Естественно, для этого нужны лямбда-выражения и замыкания. На самом деле, далеко не обязательно, чтоб выглядело буквально как for и while, но хочется, чтоб количество лишних телодвижений у пользователя было минимальным.

Базис языка (Си) очень плохо для этого подходит, ИМХО, что я и старался показать. Для достижения нормального результата (простой красивый язык) придется сказать С++ досвиданья.

ПК>Также маячит идея, что (по мотивам некоторых функциональных языков) можно более удачно, чем шаблоны C++, ввести поддержку обобщенного программирования.

Лучшее, что придумано на эту тему на данный момент — система типов Хиндли-Милнера, или нечто похожее. Примеры — система типов OCaml, Nemerle.

ПК>В частности, в определенных случаях очень полезным может оказаться откладывание определения типа выражения, что в C++ не поддерживается. Например:

ПК>
ПК>enum A { a };
ПК>enum B { b };

ПК>void foo(A);
ПК>void foo(B);

ПК>template< class T, class F >
ПК>void bar( T t, F f )
ПК>{
ПК>   f( t );
ПК>}

ПК>void g()
ПК>{
ПК>   bar( a, foo );
ПК>}
ПК>

ПК>В C++ будет неоднозначность, т.к. выбрать тип foo в точке вызова bar не удастся. Хочется, чтоб можно было bar вызвать с "недовыведенным" типом. Есть устойчивое ощущение, что введение "прозрачных" замыканий лямбда-выражений зависит от возможности отложенного выведения типов.

Здесь проблема в другом. Система не знает детали устройства типа F, в то время как в языке с системой типов Хиндли-Милнера эти детали ей известны. Из контекста bar однозначно выводится, что тип F — это функция (функтор), отображающая T в нечто, чего компилятор С++ делать просто не умеет — система типов не позволяет .

В случае системы типов Хиндли-Милнера компилятор однозначно определит сигнатуру полиморфной функции без помощи программиста.
bar:: a (a -> b) -> b
bar t f = f t
Re[22]: Примитивные конструкции языка
От: TK Лес кывт.рф
Дата: 06.07.05 22:30
Оценка: 19 (1) +1
Здравствуйте, AndrewVK, Вы писали:

AVK>Невозможность модификации контейнера это не ограничение foreach, а ограничение итераторов стандартных контейнеров.


Для справки: В C# foreach не предоставляет доступ к текущей позиции итератора. так же, как и к самому итератору. И, даже если снять ограничение на изменение итерируемых контейноров — от кривости foreach это не спасет (так и представляю себе "красоту" реализации удаления элемента из середины связянного списка на базе foreach).

Хотя, не спорю — можно и головой гвозди забивать.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[4]: Примитивные конструкции языка
От: Павел Кузнецов  
Дата: 07.07.05 00:06
Оценка:
alexeiz,

> Что мне не нравится в большинстве предложений, это то, что лямбда функции определяются внутри (). Поэтому получается, что {} скобки появляются внутри () скобок, и это очень неестественно для C-подобных языков. Так уже сделано в Java и C#. Выглядит это плохо, нечитабильно. В то же время, для родных конструкций типа for блок {} идёт сразу за конструкцией, а не находится внутри неё. Поэтому, хочется, чтобы алгоритмы выглядели как можно ближе к родным конструкциям.


Мои "мучения" начались именно с этого (плюс ниже), но сейчас к данному неудобству я отношусь уже намного спокойнее, и даже готов смириться, больше "напрягает" второе.

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


Требование явного задания сигнатуры мне кажется не менее неудачным, как и {} внутри (): тому же for никакая сигнатура для "вызова" {} не нужна. Есть устойчивое ощущение, что если применить для определения "сигнатуры" содержимого {} вывод типов, подобно некоторым функциональным языкам, то можно добиться полной аналогии с встроенными операторами. Причем, что интересно, в какой-то момент в обсуждении auto мелькали идеи возможности его использования для вывода результатов функций. Впрочем, за явное задание сигнатуры тоже есть свои аргументы...

> Далее следует вопрос, а как организовать замыкания? Наиболее логично, как мне кажется, представлять замыкания как функтор, который имеет operator() и содержит ссылки на локальный контекст.


Такая модель будет адекватно работать только в случае, если время жизни замыкания не выходит за пределы времени жизни соответствующего контекста. Впрочем, для 99%, имхо, такое ограничение проблемой не является. Но хочется, оставшийся 1% тоже можно поддержать, пусть и несколько более сложным в использовании способом. Все время маячит идея какого-то синтаксиса для создания замыканий в динамической памяти, и перекладыванию ответственности за время жизни на программиста. Нужно только как-то согласовать, что в этом случае контекст таки должен копироваться. Для того, чтоб не было путаницы, скорее всего, более правильным было бы введение различного синтаксиса для "ссылочного" и "копирующего" использования переменных из окружающих блоков в лямбда-выражениях.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.