По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.10 13:56
Оценка: 7 (1)
В ревизиях 9018 и 9019 появились новые макросы foreach / else, while / else.
Эти конструкции создают неоднозначность с if / else, что приводит к ломающим изменениям и заставляет писать лишние скобки.

Уверен, что конструкция:
if (x)
  foreach (y in ys)
    z(y);
else
  someElse();


применяется чаше чем:
foreach (y in ys)
  z(y);
else
  someElse();


Может быть лучше сделать синтаксис другим? Например, можно сделать так:
foreach (y in ys)
  z(y);
loop else
  someElse();
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: По поводу foreach / else
От: catbert  
Дата: 22.07.10 14:12
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>В ревизиях 9018 и 9019 появились новые макросы foreach / else, while / else.

VD>Эти конструкции создают неоднозначность с if / else, что приводит к ломающим изменениям и заставляет писать лишние скобки.

А что они делают и для чего понадобились?
Re: По поводу foreach / else
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 22.07.10 14:13
Оценка: :)
Здравствуйте, VladD2, Вы писали:

VD>Может быть лучше сделать синтаксис другим? Например, можно сделать так:

VD>
VD>foreach (y in ys)
VD>  z(y);
VD>loop else
VD>  someElse();
VD>


А так?

foreach (y in ys)
  z(y);
fiasco
  someElse();
Re: По поводу foreach / else
От: nikov США http://www.linkedin.com/in/nikov
Дата: 22.07.10 14:16
Оценка: 70 (4) +2
Здравствуйте, VladD2, Вы писали:

VD>Может быть лучше сделать синтаксис другим? Например, можно сделать так:

VD>
VD>foreach (y in ys)
VD>  z(y);
VD>loop else
VD>  someElse();
VD>


Может быть, так?

foreach (y in ys)
  z(y);
otherwise
  someElse();
Re[2]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.10 14:30
Оценка:
Здравствуйте, catbert, Вы писали:

C>А что они делают и для чего понадобились?


Мне кажется это ясно из подписи к комиту и прилагаемых тестов:
http://code.google.com/p/nemerle/source/detail?r=9018
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.10 14:34
Оценка:
Здравствуйте, Mystic, Вы писали:

M>А так?


M>
M>foreach (y in ys)
M>  z(y);
M>fiasco
M>  someElse();
M>


Это как из кроссворда: Слово из шести букв, вторая буква "и", означающее "крушение всех надежд".
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.10 14:36
Оценка:
Здравствуйте, nikov, Вы писали:

N>Может быть, так?


N>
N>foreach (y in ys)
N>  z(y);
N>otherwise
N>  someElse();
N>


Можно и так. Только фиаско не надо. А то я от смеха умру.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: По поводу foreach / else
От: _nn_ www.nemerleweb.com
Дата: 22.07.10 14:38
Оценка:
Здравствуйте, nikov, Вы писали:

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


VD>>Может быть лучше сделать синтаксис другим? Например, можно сделать так:

VD>>
VD>>foreach (y in ys)
VD>>  z(y);
VD>>loop else
VD>>  someElse();
VD>>


N>Может быть, так?


N>
N>foreach (y in ys)
N>  z(y);
N>otherwise
N>  someElse();
N>


Если otherwise нигде не занято, можно взять его.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.10 14:44
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Если otherwise нигде не занято, можно взять его.


Оно используется в assertions.n, но по идее конфликтов быть не должно. Или они будут настолько редки, что этим можно пренебречь.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: По поводу foreach / else
От: _nn_ www.nemerleweb.com
Дата: 22.07.10 14:57
Оценка:
Здравствуйте, VladD2, Вы писали:

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


__>>Если otherwise нигде не занято, можно взять его.


VD>Оно используется в assertions.n, но по идее конфликтов быть не должно. Или они будут настолько редки, что этим можно пренебречь.


А если не секрет как можно создать там конфликт ?
У меня никак for/while/foreach не удается вписать в блок require.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: По поводу foreach / else
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 22.07.10 15:42
Оценка: +1
Здравствуйте, VladD2, Вы писали:

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


M>>
M>>foreach (y in ys)
M>>  z(y);
M>>fiasco
M>>  someElse();
M>>


VD>Это как из кроссворда: Слово из шести букв, вторая буква "и", означающее "крушение всех надежд".

VD>

Ну да. Вообще-то я искал английский аналог для нашего родного "облом". Чтобы было с юмором (а это всегда лучше запоминается и лучше акцентируется). Плюс слово достаточно редкое, вряд ли я припомню хотя бы один идентификатор с таким именем. otherwise более официально.
Re[5]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.07.10 15:45
Оценка:
Здравствуйте, _nn_, Вы писали:

__>А если не секрет как можно создать там конфликт ?


Х.з. когда создастся, то сам увидишь .

__>У меня никак for/while/foreach не удается вписать в блок require.


А что этому мешает? Он не принимает void-выражения?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: По поводу foreach / else
От: _nn_ www.nemerleweb.com
Дата: 25.07.10 06:03
Оценка: 45 (1)
Здравствуйте, VladD2, Вы писали:

Переделал на foreach..otherwise
Теперь все должно работать без неоднозначностей.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: По поводу foreach / else
От: _nn_ www.nemerleweb.com
Дата: 25.07.10 06:05
Оценка:
Здравствуйте, VladD2, Вы писали:

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


__>>А если не секрет как можно создать там конфликт ?


VD>Х.з. когда создастся, то сам увидишь .


__>>У меня никак for/while/foreach не удается вписать в блок require.


VD>А что этому мешает? Он не принимает void-выражения?


Да.
class A
{
  public F(i : int) : int
    requires ()
  {
    i
  }
}


Error: expected bool, got void in matched value: the types void and bool are not compatible [simple unify]


А блок тоже нельзя вставить:
class A
{
  public F(i : int) : int
    requires { i > 1 }
  {
    i
  }
}


Error: parse error near '{...}' group: expecting type declaration


Так что, конфликтов здесь никак не может быть.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: По поводу foreach / else
От: Иванков Дмитрий Россия  
Дата: 26.07.10 09:48
Оценка: 12 (1)
Здравствуйте, VladD2, Вы писали:

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


C>>А что они делают и для чего понадобились?


VD>Мне кажется это ясно из подписи к комиту и прилагаемых тестов:

VD>http://code.google.com/p/nemerle/source/detail?r=9018

то есть они делают совсем не то, что в питоне делают for-else (else-тело выполняется, если цикл не завершился break-ом) и while-else (выполняется, если цикл завершился по false == условие цикла), а выполняют else-тело, если основное тело не было вызвано ни разу. Все три варианта поведения мягко говоря не интуитивны. Как минимум, в документации должно быть отражено отличие от python.
Re[4]: По поводу foreach / else
От: _nn_ www.nemerleweb.com
Дата: 26.07.10 11:43
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

ИД>Здравствуйте, VladD2, Вы писали:


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


C>>>А что они делают и для чего понадобились?


VD>>Мне кажется это ясно из подписи к комиту и прилагаемых тестов:

VD>>http://code.google.com/p/nemerle/source/detail?r=9018

ИД> то есть они делают совсем не то, что в питоне делают for-else (else-тело выполняется, если цикл не завершился break-ом) и while-else (выполняется, если цикл завершился по false == условие цикла), а выполняют else-тело, если основное тело не было вызвано ни разу. Все три варианта поведения мягко говоря не интуитивны. Как минимум, в документации должно быть отражено отличие от python.


Насчет break-ов действительно не подумал.
Доделать не сложно
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: По поводу foreach / else
От: _nn_ www.nemerleweb.com
Дата: 26.07.10 13:37
Оценка:
Здравствуйте, _nn_, Вы писали:

Оказалось немного запутанней чем я предполагал:

Вот новый макрос
  macro @while (cond, body, otherwiseBody)
  syntax ("while", "(", cond, ")", body, Optional("otherwise", otherwiseBody))
  {
    def otherwiseBody = otherwiseBody ?? <[ ]>;
    
    <[ 
      ($("_N_break" : global) : {
        def loop () : void
        {
          when ($cond)
          {
            ($("_N_continue" : global) : {
              $body
            }) : void;
            loop ()
          }
        }
        
        loop ();
        
        $otherwiseBody
      }) : void
    ]>
  }


Он прекрасно работает в коде и даже проходит тесты.

Одна загвоздка в нем. Его нельзя использовать в макросах.
macro FFF(c)
  {
    <[
      while (false) {}
    ]>
  }

Error: parse error near '{...}' group: unexpected token after expression in sequence (you forget a closing bracket?).


Как всегда вопросы: кто виноват и что делать ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 13:40
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Он прекрасно работает в коде и даже проходит тесты.

__>Одна загвоздка в нем. Его нельзя использовать в макросах.
__>Как всегда вопросы: кто виноват и что делать ?

Насколько мне известно в квази-цитатах используется все тот же парсер, так что по идее если код компилируется вне цитаты, то в цитате тоже должен. Так что надо смотреть под отладчиком что происходит.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 13:42
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Как всегда вопросы: кто виноват и что делать ?


А почему ты не остановился на отдельном макросе?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 13:47
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

ИД> то есть они делают совсем не то, что в питоне делают for-else (else-тело выполняется, если цикл не завершился break-ом)


Э... а разве не в случае когда в коллекции нет элементов? Кстати, я бы еще хотел чтобы чтобы на null тоже else срабатывал.

ИД>и while-else (выполняется, если цикл завершился по false == условие цикла), а выполняют else-тело, если основное тело не было вызвано ни разу.


Тут я вообще ничего не понял. Мне казалось, то любой вид цикла должен вызвать else если основной цикл не сработал ни разу. Зачем еще какие-то "завершился по false == условие цикла"?

ИД>Все три варианта поведения мягко говоря не интуитивны. Как минимум, в документации должно быть отражено отличие от python.


В общем, я стал понимать еще меньше чем в начале. Можно объяснить все более подробно и доступно (для тех кто с Питоном не на "ты")?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 13:49
Оценка:
Здравствуйте, _nn_, Вы писали:


VD>>А что этому мешает? Он не принимает void-выражения?


__>Да.

__>

__>Error: expected bool, got void in matched value: the types void and bool are not compatible [simple unify]


ОК, тогда делай otherwise. else слишком конфликтный.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: По поводу foreach / else
От: _nn_ www.nemerleweb.com
Дата: 26.07.10 13:57
Оценка:
Здравствуйте, VladD2, Вы писали:

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


__>>Как всегда вопросы: кто виноват и что делать ?


VD>А почему ты не остановился на отдельном макросе?


Мне надо otherwiseBody поместить в блок _N_Break, как раз одним макросом все красиво решалось..

Получилось локализовать проблему, вроде:
  macro While1 (cond, body)
  syntax ("while1", "(", cond, ")", body)
  {
    <[
    ]>
  }
  
  macro While2 (cond, body, otherwiseBody)
  syntax ("while1", "(", cond, ")", body, "otherwise", otherwiseBody)
  {
    <[ 
    ]>
  }
  
  macro FFF()
  {
    <[
      while1 (false) ; { }
    ]>
  }

  macro GGG()
  {
    <[
      while1 (false) { } //  Error: parse error near '{...}' group: unexpected token after expression in sequence (you forget a closing bracket?).
    ]>
  }


Почему в FFF нужна ";" между while1 и скобками ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[8]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 14:06
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Мне надо otherwiseBody поместить в блок _N_Break, как раз одним макросом все красиво решалось..


Ясно.

А зачем в _N_Break?

Но, проблема в том, что foreach уже и так очень перегружен. Добавление к нему еще кода усложнит его многократно.

__>Получилось локализовать проблему, вроде:

__>
__>  macro While1 (cond, body)
__>  syntax ("while1", "(", cond, ")", body)...
__>  macro While2 (cond, body, otherwiseBody)
__>  syntax ("while1", "(", cond, ")", body, "otherwise", otherwiseBody)...
__>  macro FFF()
__>  {
__>    <[
__>      while1 (false) ; { }
__>    ]>
__>  }
__>


__>Почему в FFF нужна ";" между while1 и скобками ?


Без пары часов под отладчиком я тебе на этот вопрос не отвечу .
Но если приглядеться к реализации if/else, то можно заметить некий трюк:
  macro @if (cond, e1, e2)
  syntax ("if", "(", cond, ")", e1, Optional (";"), "else", e2)

Осмелюсь предположить, что выделенное жирным решает туже самую проблему.

Попробуй добавить это дело и в while.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: По поводу foreach / else
От: _nn_ www.nemerleweb.com
Дата: 26.07.10 14:11
Оценка:
Здравствуйте, VladD2, Вы писали:

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


__>>Мне надо otherwiseBody поместить в блок _N_Break, как раз одним макросом все красиво решалось..


VD>Ясно.


VD>А зачем в _N_Break?

Для соответствия со спецификацией Python: http://docs.python.org/reference/compound_stmts.html
Вкратце, если вызвался break,то не вызывать otherwiseBlock.

__>>Почему в FFF нужна ";" между while1 и скобками ?


VD>Без пары часов под отладчиком я тебе на этот вопрос не отвечу .

VD>Но если приглядеться к реализации if/else, то можно заметить некий трюк:
VD>
VD>  macro @if (cond, e1, e2)
VD>  syntax ("if", "(", cond, ")", e1, Optional (";"), "else", e2)  
VD>

VD>Осмелюсь предположить, что выделенное жирным решает туже самую проблему.

VD>Попробуй добавить это дело и в while.



Попробую позже.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[10]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 14:14
Оценка:
Здравствуйте, _nn_, Вы писали:

VD>>А зачем в _N_Break?

__>Для соответствия со спецификацией Python: http://docs.python.org/reference/compound_stmts.html
__>Вкратце, если вызвался break,то не вызывать otherwiseBlock.

Погоди, но разве он вообще должен вызваться если мы вошли в тело цикла? Мне показалось, что твоя реализация при первом же входе поднимает флаг предотвращающий вызов otherwise при входе в тело цикла.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: По поводу foreach / else
От: Иванков Дмитрий Россия  
Дата: 26.07.10 14:53
Оценка:
Здравствуйте, VladD2, Вы писали:
VD>В общем, я стал понимать еще меньше чем в начале. Можно объяснить все более подробно и доступно (для тех кто с Питоном не на "ты")?

http://docs.python.org/reference/compound_stmts.html#the-while-statement
http://docs.python.org/reference/compound_stmts.html#the-for-statement

Смысл примерно такой, что перед каждым входом в тело цикла проверяется условие, и в случае false цикл просто прерывается, вот перед этим моментом вставляется else-выражение.
То есть для for/while вызов происходит при выходе по условию цикла, но не по break.
С Питоном я тоже не на "ты", но вроде бы обычно это используют для циклов, осуществляющих какой-нибудь поиск.
Re[11]: По поводу foreach / else
От: _nn_ www.nemerleweb.com
Дата: 26.07.10 14:56
Оценка:
Здравствуйте, VladD2, Вы писали:

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


VD>>>А зачем в _N_Break?

__>>Для соответствия со спецификацией Python: http://docs.python.org/reference/compound_stmts.html
__>>Вкратце, если вызвался break,то не вызывать otherwiseBlock.

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


Первоначальный вариант был неправильным как подмеченно здесь http://rsdn.ru/forum/nemerle/3892867.1.aspx
Автор: Иванков Дмитрий
Дата: 26.07.10
.
Я начал исправлять и наткнулся на проблемы.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 15:04
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

ИД> то есть они делают совсем не то, что в питоне делают for-else (else-тело выполняется, если цикл не завершился break-ом) и while-else (выполняется, если цикл завершился по false == условие цикла), а выполняют else-тело, если основное тело не было вызвано ни разу. Все три варианта поведения мягко говоря не интуитивны. Как минимум, в документации должно быть отражено отличие от python.


Цитата из доки по Питону:
http://docs.python.org/reference/compound_stmts.html#grammar-token-for_stmt

When the items are exhausted (which is immediately when the sequence is empty), the suite in the else clause, if present, is executed, and the loop terminates.


Я правильно понимаю, что в Питоне else вызывается даже если коллекция не пуста?
Если это так, то кто-нибудь может объяснить великий смысл этого этого подхода? Т.е. зачем так делать?
Мне кажется, что в этом просто нет смысла. Вот else в случае если коллекция пуста или null имеет смысл, так как это позволяет нам обработать нештатную ситуацию (хотя ее и так не сложно обработать проверив длину коллекции). Но какой смысл в вызове else для не пустой коллекции? Да звучит "else" при этом не интуитивно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 15:08
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

ИД>http://docs.python.org/reference/compound_stmts.html#the-while-statement

ИД>http://docs.python.org/reference/compound_stmts.html#the-for-statement

ИД>Смысл примерно такой, что перед каждым входом в тело цикла проверяется условие, и в случае false цикл просто прерывается, вот перед этим моментом вставляется else-выражение.

ИД>То есть для for/while вызов происходит при выходе по условию цикла, но не по break.
ИД>С Питоном я тоже не на "ты", но вроде бы обычно это используют для циклов, осуществляющих какой-нибудь поиск.

На мой взгляд какое-то совершенно бессмысленное поведение (если я его правильно понял).

Вот выполнить действия если в тело цикла не попали вовсе смысл имеет.

Или тогда уж нужно называть эту конструкцию не else/otherwise, а after, что ли.

В общем, хотелось бы увидеть некий случай использования питоновского поведения. А то пока я что-то не пойму какую цель решает их реализация.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 15:09
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Первоначальный вариант был неправильным как подмеченно здесь http://rsdn.ru/forum/nemerle/3892867.1.aspx
Автор: Иванков Дмитрий
Дата: 26.07.10
.

__>Я начал исправлять и наткнулся на проблемы.

Вот можно по подробнее об этих проблемах. А то я что-то не догоняю.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: По поводу foreach / else
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 26.07.10 15:21
Оценка:
Здравствуйте, VladD2, Вы писали:

ИД>>Все три варианта поведения мягко говоря не интуитивны. Как минимум, в документации должно быть отражено отличие от python.

VD>В общем, я стал понимать еще меньше чем в начале. Можно объяснить все более подробно и доступно (для тех кто с Питоном не на "ты")?

Питоновский for — это аналог немерловского и шарпового foreach, итерирует некую последовательность, помещая очередной элемент в заданную переменную. Else там выполняется тогда, когда больше нечего итерировать, т.е. после того, как достигнут конец последовательности. Если последовательность пуста, то else выполняется сразу. Соответственно, если из цикла вышли по break, то else не выполняется (т.к. не был достигнут конец последовательности), если из итерации вышли по continue, то else выполняется, если на текущий момент в последовательности не осталось элементов.

Питоновский while — по логике аналогичен одноименному циклу в немерле и шарпе. Пока выполняется какое-либо условие, выполняется тело цикла, как только условие перестало выполнятся, то однократно выполняется else и цикл завершается. Если из цикла вышли по break (или из итерации по continue), то else не выполняется.

Иными словами, else — это набор инструкций, которые должны быть выполнены в том случае, если цикл уже завершен, но только в том случае, если в ходе работы цикла были осуществлены все запланированные по его логике итерации.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>

[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re[6]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 15:21
Оценка:
Здравствуйте, Иванков Дмитрий, Вы писали:

ИД>http://docs.python.org/reference/compound_stmts.html#the-while-statement

ИД>http://docs.python.org/reference/compound_stmts.html#the-for-statement

ИД>Смысл примерно такой, что перед каждым входом в тело цикла проверяется условие, и в случае false цикл просто прерывается, вот перед этим моментом вставляется else-выражение.

ИД>То есть для for/while вызов происходит при выходе по условию цикла, но не по break.
ИД>С Питоном я тоже не на "ты", но вроде бы обычно это используют для циклов, осуществляющих какой-нибудь поиск.

Иными словами else срабатывает всегда за исключением случая выхода из цикла по break?

Единственное что приходит на ум по поводу "зачем это надо" — это эмуляция метода Find или даже FindWithDefault.
Есть ли какие-то еще варианты использования для питоновского else-а?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 15:23
Оценка:
Здравствуйте, kochetkov.vladimir, Вы писали:

KV>Иными словами, else — это набор инструкций, которые должны быть выполнены в том случае, если цикл уже завершен, но только в том случае, если в ходе работы цикла были осуществлены все запланированные по его логике итерации.


Это я уже понял. Но какой в этом практический смысл?

Каковы варианты использования этого дела? Другими словами что это дает на практике?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: По поводу foreach / else
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 26.07.10 15:24
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Я правильно понимаю, что в Питоне else вызывается даже если коллекция не пуста?

VD>Если это так, то кто-нибудь может объяснить великий смысл этого этого подхода? Т.е. зачем так делать?
VD>Мне кажется, что в этом просто нет смысла. Вот else в случае если коллекция пуста или null имеет смысл, так как это позволяет нам обработать нештатную ситуацию (хотя ее и так не сложно обработать проверив длину коллекции). Но какой смысл в вызове else для не пустой коллекции? Да звучит "else" при этом не интуитивно.

else в питоне предназначен как раз для обратного: для обработки ситуации, когда цикл отработал штатно и не прервался каким-либо образом.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>

[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re[6]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 15:41
Оценка:
Здравствуйте, kochetkov.vladimir, Вы писали:

KV>else в питоне предназначен как раз для обратного: для обработки ситуации, когда цикл отработал штатно и не прервался каким-либо образом.


Понял, понял я уже. Я не понял зачем это все нужно? Для чего это все используется?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: По поводу foreach / else
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 26.07.10 15:55
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Есть ли какие-то еще варианты использования для питоновского else-а?


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

Как еще один из возможных вариантов применения — возврат циклом каких-либо значений, т.е. сделать цикл псевдо-выражением.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>

[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re[8]: По поводу foreach / else
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 26.07.10 16:12
Оценка:
Здравствуйте, kochetkov.vladimir, Вы писали:
KV>Здравствуйте, VladD2, Вы писали:

VD>>Есть ли какие-то еще варианты использования для питоновского else-а?

KV>В общем, идей, почему Гвидо впихнул туда этот синтаксис нет.

Все-таки вот это.:

KV>Скорее всего, чтобы сделать более красивой работу с циклами, в которых возводятся какие-либо булевы флаги.


Он ввел это в синтаксис именно для того, чтобы в циклах с break была возможность разветвлить control-flow в зависимости от того, каким образом был осуществлен выход из цикла.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>

[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re[8]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 16:19
Оценка: 11 (1) +1
Здравствуйте, kochetkov.vladimir, Вы писали:

KV>Как еще один из возможных вариантов применения — возврат циклом каких-либо значений, т.е. сделать цикл псевдо-выражением.


Все равно не ясно что возвращать при этом.

ЗЫ

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

ЗЫЫ

Подозреваю что else в Питоне был создан для поиска значений в коллекциях путем их полного перебора. Но циклы для этого не очень подходящий механизм. Намного удобнее для этого использовать методы Find, FindIndex, Where, Filter.

Так может быть вместо этого самого else/otherwise лучше создать некий макрос find, который позволит сделать синтаксис поиска более компактным, а сам поиск более эффективным? Синтаксис может быть примерно таким:
"find" "(" id "when" condition ("with" index)? "in" collection ")" body ("notfound" expr)?

где
id         : PExpr.Ref
condition  : PExpr
index      : PExpr
collection : PExpr
body       : PExpr
expr       : PExpr

Примеры использования:
def res = find (x when x > 10 && x % 2 == 0 in [1 .. 100]) x * 42 notfound 0;

// или императивный (возвращающий void) вариант:
mutable res;

find (x when x > 10 && x % 2 == 0 in [1 .. 100])
  res = x; // тут...
notfound
  res = 0; // и тут, естественно, могут быть любые выражения, в том числе блок кода.

Вариант с индексом и без notfound:
def ary = arry[1 .. 100];

find (x when x > 10 with i && x % 2 == 0 in )
  ary[i] = x * 42; // тут...


Это будет намного удобнее нежели не очевидный otherwise в циклах, которые в Немерле очень редко используются (людьми хорошо знакомыми с Немерле) для поиска значений.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: По поводу foreach / else
От: WolfHound  
Дата: 26.07.10 16:42
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Пока что у меня усиливается ощущение, что данная фича добавляется чтобы говорить другим "у нас это тоже есть". А это мне категорически не нравится. В язык нужно пихать только то, что используется часто и дает видимый эффект.

+1

VD>Так может быть вместо этого самого else/otherwise лучше создать некий макрос find, который позволит сделать синтаксис поиска более компактным, а сам поиск более эффективным? Синтаксис может быть примерно таким:

VD>
VD>"find" "(" id "when" condition ("with" index)? "in" collection ")" body ("notfound" expr)?
VD>

Вместо id "when" condition нужен полноценный паттерн.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: По поводу foreach / else
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 26.07.10 16:43
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Это будет намного удобнее


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

VD>нежели не очевидный otherwise в циклах, которые в Немерле очень редко используются (людьми хорошо знакомыми с Немерле) для поиска значений.


Тут еще такая мысль появилась... Сейчас к телам циклов предъявляется требование, чтобы они имели тип void, насколько я понимаю. Соответственно, у цикла также нет возвращаемого значения. А вот если бы цикл был выражением, возвращающим список, элементами которого бы являлись значения, полученные на каждой из итераций, то тогда попадание в otherwise можно было бы завязать на условие того, что возвращенный список является пустым.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>

[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re[10]: По поводу foreach / else
От: kochetkov.vladimir Россия https://kochetkov.github.io
Дата: 26.07.10 16:49
Оценка:
Здравствуйте, kochetkov.vladimir, Вы писали:

KV>Тут еще такая мысль появилась... Сейчас к телам циклов предъявляется требование, чтобы они имели тип void, насколько я понимаю. Соответственно, у цикла также нет возвращаемого значения. А вот если бы цикл был выражением, возвращающим список, элементами которого бы являлись значения, полученные на каждой из итераций, то тогда попадание в otherwise можно было бы завязать на условие того, что возвращенный список является пустым.


Не, фигня, на вложенных и развесистых циклах где эта фича не потребуется, GC охренеет
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>

[Интервью] .NET Security — это просто
Автор: kochetkov.vladimir
Дата: 07.11.17
Re[10]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 17:01
Оценка:
Здравствуйте, WolfHound, Вы писали:

VD>>
VD>>"find" "(" id "when" condition ("with" index)? "in" collection ")" body ("notfound" expr)?
VD>>

WH>Вместо id "when" condition нужен полноценный паттерн.

Да, согласен, так будет лучше (так же как в foreach и более гибко). Только обсуждать это дело лучше здесь:
http://rsdn.ru/forum/nemerle/3893599.1.aspx
Автор: VladD2
Дата: 26.07.10
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: По поводу foreach / else
От: Аноним  
Дата: 26.07.10 17:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Может быть лучше сделать синтаксис другим? Например, можно сделать так:

foreach (y in ys) {
} on empty list {
// вызывается если foreach ни разу не сработал
} on one item exist in list {
// вызывается если foreach сработал один раз
} on break {
// вызывается если в foreach был вызван break
} on continue {
// вызывается если в foreach был вызван continue
}


или так

try_for_each (y in ys) {
} catch_empty list {
// вызывается если foreach ни разу не сработал
} catch_one_item_exist_in_list {
// вызывается если foreach сработал один раз
} catch_break {
// вызывается если в foreach был вызван break
} catch_continue {
// вызывается если в foreach был вызван continue
}
Re[10]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 17:06
Оценка:
Здравствуйте, kochetkov.vladimir, Вы писали:

VD>>Это будет намного удобнее


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


С этого места плиз по подробнее, со ссылкаи, и лучше беседу продолжать здесь:
http://rsdn.ru/forum/nemerle/3893599.1.aspx
Автор: VladD2
Дата: 26.07.10

так ее увидит больше народа.

VD>>нежели не очевидный otherwise в циклах, которые в Немерле очень редко используются (людьми хорошо знакомыми с Немерле) для поиска значений.


KV>Тут еще такая мысль появилась... Сейчас к телам циклов предъявляется требование, чтобы они имели тип void, насколько я понимаю. Соответственно, у цикла также нет возвращаемого значения. А вот если бы цикл был выражением, возвращающим список, элементами которого бы являлись значения, полученные на каждой из итераций, то тогда попадание в otherwise можно было бы завязать на условие того, что возвращенный список является пустым.


В Питоне в else попадают всегда если не был вызван break. Так что этой твоей фразы я вообще не понял.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 17:07
Оценка:
Здравствуйте, kochetkov.vladimir, Вы писали:

KV>>Тут еще такая мысль появилась... Сейчас к телам циклов предъявляется требование, чтобы они имели тип void, насколько я понимаю. Соответственно, у цикла также нет возвращаемого значения. А вот если бы цикл был выражением, возвращающим список, элементами которого бы являлись значения, полученные на каждой из итераций, то тогда попадание в otherwise можно было бы завязать на условие того, что возвращенный список является пустым.


KV>Не, фигня, на вложенных и развесистых циклах где эта фича не потребуется, GC охренеет


ЖЦ то тут причем? Ему вообще все это до лампочки. Объекты умершие до запуска GC попросту не считаются родившимися.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 17:26
Оценка:
Здравствуйте, Аноним, Вы писали:

VD>>Может быть лучше сделать синтаксис другим? Например, можно сделать так:

А>
А>foreach (y in ys) {
А>} on empty list {
А>// вызывается если foreach ни разу не сработал
А>} on one item exist in list {
А>// вызывается если foreach сработал один раз
А>} on break {
А>// вызывается если в foreach был вызван break
А>} on continue {
А>// вызывается если в foreach был вызван continue
А>}
А>


Что касается on empty list, то первая реализация else это и делала. Но оказалось, что это не тоже поведение что и в Питоне и поведение было решено сделать как в Питоне. А я вот пока что не пойму зачем оно такое нужно.

Что касается остального, то это какой то несусветный перебор. Да и "слишком много букв".

Кроме того не ясно зачем может понадобиться "on one item exist in list"? Вот выполнение для первого элемента, если это удастся реализовать более компактно, могло бы быть весьма полезным. Частенько бывает, что обработка для первого элемента отличается от остальных. Но это все уже совсем не о foreach / else.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: По поводу foreach / else
От: Аноним  
Дата: 26.07.10 17:41
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Аноним, Вы писали:


VD>Что касается on empty list, то первая реализация else это и делала. Но оказалось, что это не тоже поведение что и в Питоне и поведение было решено сделать как в Питоне. А я вот пока что не пойму зачем оно такое нужно.


Я так понял были проблемы с однозначностью в блоке if/else.
Соответственно два предложения по именованию, первое в стиле реакции на события (on click), второй в стиле try/catch.

VD>Что касается остального, то это какой то несусветный перебор. Да и "слишком много букв".

Я полагаю, что отдельные блоки можно и нужно делать опциональными.
К тому же можно и сократить on_empty, on_one_item, on_catch, on_continue.

VD>Кроме того не ясно зачем может понадобиться "on one item exist in list"? Вот выполнение для первого элемента, если это удастся реализовать более компактно, могло бы быть весьма полезным. Частенько бывает, что обработка для первого элемента отличается от остальных. Но это все уже совсем не о foreach / else.


on_one_item это отрицание on_empty.

Зачем может понадобиться

foreach(var item in list) {
  Response.Write("Товар: " + item.Name + "\n");
} on_one_item {
  Response.Write("Всего товаров: " + list.Count);
} on_empty {
  Response.Write("Нет товаров");
}


Соответственно если товары в списке есть, то выведет список товаров и их количество, если же нет товаров то так и напишет.
Re[4]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 17:58
Оценка:
Здравствуйте, Аноним, Вы писали:

VD>>Что касается остального, то это какой то несусветный перебор. Да и "слишком много букв".

А>Я полагаю, что отдельные блоки можно и нужно делать опциональными.

Проблема с неоднозначностью снялась предложением nikov-а использовать otherwise.

А>К тому же можно и сократить on_empty, on_one_item, on_catch, on_continue.


Для ключевых слов не принято использовать подчеркивания, а я за традиции.

VD>>Кроме того не ясно зачем может понадобиться "on one item exist in list"? Вот выполнение для первого элемента, если это удастся реализовать более компактно, могло бы быть весьма полезным. Частенько бывает, что обработка для первого элемента отличается от остальных. Но это все уже совсем не о foreach / else.


А>on_one_item это отрицание on_empty.


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

А>Зачем может понадобиться


А>
А>foreach(var item in list) {
А>  Response.Write("Товар: " + item.Name + "\n");
А>} on_one_item {
А>  Response.Write("Всего товаров: " + list.Count);
А>} on_empty {
А>  Response.Write("Нет товаров");
А>}
А>


То честь, предлагается не смотря на вызов on_one_item все равно вызвать тело цикла после вызвоа on_one_item?
Я понял это так, что on_one_item вызывается вместо тела цикла для первого элемента коллекции.

Но тут встает вопрос насколько это нужно? Ведь тоже самое достигается с помощью:
if (lst.IsEmpty)
  Response.Write("Нет товаров")
else
  Response.Write("Всего товаров: " + list.Count);

foreach(var item in lst)
  Response.Write("Товар: " + item.Name + "\n");

Я тут недавно делал XML-литералы
Автор: VladD2
Дата: 21.07.10
и я намеренно не стал делать поддержки подобных развернутых конструкций. Это нарушает принцип KISS.
Для данного примера код использующий ХМЛ-литералы будет выглядеть так:
<p $when    (lst.IsEmpty)>Нет товаров</p>
<p $unless  (lst.IsEmpty)>Всего товаров $(list.Length)</p>
<p $foreach (item in lst)>Всего товаров $(item.Name)</p>

с той разницей, что при это генерируется не плоский текст, а XML.

А>Соответственно если товары в списке есть, то выведет список товаров и их количество, если же нет товаров то так и напишет.


Ясно, но это не дает видимого преимущества. При этом программисты (даже те кто не использует эту фичу) будут вынуждены учить все эти прибамбасы в макросах. Так что я бы сказал — овчинка выделки не стоит.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: По поводу foreach / else
От: Аноним  
Дата: 26.07.10 18:00
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Частенько бывает, что обработка для первого элемента отличается от остальных. Но это все уже совсем не о foreach / else.


foreach(item in list) {
  Response.Write("Товар: " + item.Name);
} on_first {
  Response.Write("Товар: <b>" + item.Name + "</b>")
}


то есть если есть блок on_first то для первого элемента коллекции выполняется он
В данном случае для первого товара название будет выведено жирным шрифтом.
Конечно, для достаточно длинного блока foreach будет не так наглядно.

Можно также сделать on_before_first и on_after_first для действий выполняемых перед и после первого элемента.

foreach(item in list) {
  Response.Write("Товар: " + item.Name);
} on_before_first {
  Response.Write("<b>")
} on_after_first {
  Response.Write("</b>")
}
Re[4]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 18:13
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>foreach(item in list) {
А>  Response.Write("Товар: " + item.Name);
А>} on_first {
А>  Response.Write("Товар: <b>" + item.Name + "</b>")
А>}
А>


А>то есть если есть блок on_first то для первого элемента коллекции выполняется он

А>В данном случае для первого товара название будет выведено жирным шрифтом.
А>Конечно, для достаточно длинного блока foreach будет не так наглядно.

Вроде бы в прошлом примере on_first вызывался не вместо первого элемента, а перед ним.
В любом случае тоже самое можно реализовать сегодняшними средсвами практически не теряя в выразительности и скорости:
foreach(item with index in lst)
  if (index == 1)
    Response.Write("Товар: <b>" + item.Name + "</b>")
  else
    Response.Write("Товар: " + item.Name);


А>Можно также сделать on_before_first и on_after_first для действий выполняемых перед и после первого элемента.


А>
А>foreach(item in list) {
А>  Response.Write("Товар: " + item.Name);
А>} on_before_first {
А>  Response.Write("<b>")
А>} on_after_first {
А>  Response.Write("</b>")
А>}
А>


Ага, можно. Но опять же вариант с индексом проще и универсальнее ведь он позволит и последний элемент отработать, и четный/не четный и т.п.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: По поводу foreach / else
От: Аноним  
Дата: 26.07.10 18:14
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Аноним, Вы писали:


VD>Проблема с неоднозначностью снялась предложением nikov-а использовать otherwise.

otherwise кстати тоже очень хорошее слово, хочется часто использовать, почти как else.

VD>Для ключевых слов не принято использовать подчеркивания, а я за традиции.

может пробел тогда вместо подчеркивания


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

Ну почему частный, это отрицание else/otherwise, то есть достаточно общий.
one не означает, что только один элемент в коллекции, а хотя бы один.

VD>То честь, предлагается не смотря на вызов on_one_item все равно вызвать тело цикла после вызвоа on_one_item?

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


VD>Но тут встает вопрос насколько это нужно? Ведь тоже самое достигается с помощью:

Так такой же вопрос можно задать и для else/otherwise.

VD>
VD>if (lst.IsEmpty)
VD>  Response.Write("Нет товаров")
VD>else
VD>  Response.Write("Всего товаров: " + list.Count);

VD>foreach(var item in lst)
VD>  Response.Write("Товар: " + item.Name + "\n");
VD>


А нужно это может быть затем, что операция определения пустой список или нет может быть сравнительно дорогой.
То есть вызов метода, по сравнению с заведением локальной булевской переменной на стеке
Типа заворачивания в макрос подобного кода.
def empty = true
foreach(item in list) {
   empty = false;
}
if (empty) Response.Write("Нет товаров")
if (!empty) Response.Write("Всего товаров: " + list.Count)

Конечно, с некоей оптимизацией, чтобы присваивание было не в каждой итерации, а только в первой.


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

Ну это зависит от того, насколько просто добавить.
К тому же как я предложил, можно сделать новый макрос, try_foreach, по аналогии с TryCast, TryParse
То есть тем кто использует foreach все эти фишки учить не надо
Re[5]: По поводу foreach / else
От: Аноним  
Дата: 26.07.10 18:26
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Аноним, Вы писали:


А>>
А>>foreach(item in list) {
А>>  Response.Write("Товар: " + item.Name);
А>>} on_first {
А>>  Response.Write("Товар: <b>" + item.Name + "</b>")
А>>}
А>>


А>>то есть если есть блок on_first то для первого элемента коллекции выполняется он

А>>В данном случае для первого товара название будет выведено жирным шрифтом.
А>>Конечно, для достаточно длинного блока foreach будет не так наглядно.

VD>Вроде бы в прошлом примере on_first вызывался не вместо первого элемента, а перед ним.

Там был on_one, а не on_first. Можно вместо on_one использовать on_non_empty или on_full_list.

VD>В любом случае тоже самое можно реализовать сегодняшними средсвами практически не теряя в выразительности и скорости:

VD>
VD>foreach(item with index in lst)
VD>  if (index == 1)
VD>    Response.Write("Товар: <b>" + item.Name + "</b>")
VD>  else
VD>    Response.Write("Товар: " + item.Name);
VD>

Да, но будет некая потеря (мелкая конечно) в производительности, так как в теле цикла каждый раз выполняется проверка на индекс.
Мне кажется просто, что в явном указании есть больший простор для оптимизации.
То есть такой код
foreach (item in list) {
  Response.Write("Товар: " + item.Name)
} on_first {
  Response.Write("Товар: <b>" + item.Name + "</b>")
}

можно прямо в макросе развернуть, во что-то вроде

def item1 = list.GetNext()
if (item1 != null) Response.Write("Товар: <b>" + item.Name + "</b>");
def item = list.GetNext()
while(item != null) {
  Response.Write("Товар: " + item.Name)
  item = list.GetNext()
}


Хотя всё это возможно экономия на копейках

VD>Ага, можно. Но опять же вариант с индексом проще и универсальнее ведь он позволит и последний элемент отработать, и четный/не четный и т.п.

Это верно, код универсальнее, зато ключевые слова строже.
Re[6]: По поводу foreach / else
От: Аноним  
Дата: 26.07.10 18:36
Оценка:
Здравствуйте, Аноним, Вы писали:


А>
А>foreach (item in list) {
А>  Response.Write("Товар: " + item.Name)
А>} on_first {
А>  Response.Write("Товар: <b>" + item.Name + "</b>")
А>}
А>


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

foreach (item in list) 
on_first_item {
  Response.Write("Товар: <b>" + item.Name + "</b>")
}
on_rest_items {
  Response.Write("Товар: " + item.Name)
}
Re[6]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 18:51
Оценка:
Здравствуйте, Аноним, Вы писали:

VD>>
VD>>if (lst.IsEmpty)
VD>>  Response.Write("Нет товаров")
VD>>else
VD>>  Response.Write("Всего товаров: " + list.Count);

VD>>foreach(var item in lst)
VD>>  Response.Write("Товар: " + item.Name + "\n");
VD>>


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


Я таких коллекций не знаю. Длинна там еще может вычисляться относительно дорого (т.е. O(n)), но узнать пуста коллекция или нет всегда можно за время O(1).

А>То есть вызов метода, по сравнению с заведением локальной булевской переменной на стеке

А>Типа заворачивания в макрос подобного кода.
А>
А>def empty = true
А>foreach(item in list) {
А>   empty = false;
А>}
А>if (empty) Response.Write("Нет товаров")
А>if (!empty) Response.Write("Всего товаров: " + list.Count)
А>

А>Конечно, с некоей оптимизацией, чтобы присваивание было не в каждой итерации, а только в первой.

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

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

А>Ну это зависит от того, насколько просто добавить.

Это без относительности простоты добавления.

А>К тому же как я предложил, можно сделать новый макрос, try_foreach, по аналогии с TryCast, TryParse

А>То есть тем кто использует foreach все эти фишки учить не надо

Мы говорим о стандартной библиотеке макросов языка. Это почти одно и тоже что синтаксис языка без макросов. Мне кажется, что подобные штуки тут не уместны. В какой-нить библиотеке-расширении еще куда не шло. Но язык в базе свой должен быть чист и интуитивно понятен. Всякие try_foreach это уже перебор. О нем все равно придется знать тем кто пишет на этом языке.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 19:06
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Там был on_one, а не on_first. Можно вместо on_one использовать on_non_empty или on_full_list.


Вот, вот. И получается что людям придется изучать все эти лингвистические тонкости. А это уже не хорошо. foreach хорош тем, что он очень прост как в запоминании, так и применении. Его расширения должны быть интуитивно понятны и легки в запоминании. Иначе язык прерваться в очередной Личп, который крут, но большинству людей не понятен.

VD>>В любом случае тоже самое можно реализовать сегодняшними средсвами практически не теряя в выразительности и скорости:

VD>>
VD>>foreach(item with index in lst)
VD>>  if (index == 1)
VD>>    Response.Write("Товар: <b>" + item.Name + "</b>")
VD>>  else
VD>>    Response.Write("Товар: " + item.Name);
VD>>

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

Дык все равно при реализации какие-то проверки будут. К тому же проверка целого числа — это практически бесплатно. Особенно в сравнении с аналогичным применением функций высшего порядка и тем более Linq-а.

А>Мне кажется просто, что в явном указании есть больший простор для оптимизации.

А>То есть такой код
А>
А>foreach (item in list) {
А>  Response.Write("Товар: " + item.Name)
А>} on_first {
А>  Response.Write("Товар: <b>" + item.Name + "</b>")
А>}
А>

А>можно прямо в макросе развернуть, во что-то вроде

Да, несомненно — есть. Но это уже ловля блох. Реального ускорения приложения от этого не будет. Это будет пара выигранных тактов на фоне миллионов тактов приходящихся на само тело цикла. Если же мне захочется сгенерировать очень оптимальный код, то я скорее всего обойдусь рекурсивными функциями, т.е. вообще без макросов. Получится не так компактно, но зато гарантированно эффективно. Макрос же — это удобный и компактный синтаксис при близкой к идеальности производительности.

А>
А>def item1 = list.GetNext()
А>if (item1 != null) Response.Write("Товар: <b>" + item.Name + "</b>");
А>def item = list.GetNext()
А>while(item != null) {
А>  Response.Write("Товар: " + item.Name)
А>  item = list.GetNext()
А>}
А>


А>Хотя всё это возможно экономия на копейках


Ага. По сравнению с list.GetNext() (точнее там будет MoveNext и Current, но это детали) проверка индекса не будет стоить ровным счетом ничего. Другое дело что при доступе к массивам можно сгенерировать более эффективный код. Но там придется проверять тот же самый индекс, и разница опять же не будет.

VD>>Ага, можно. Но опять же вариант с индексом проще и универсальнее ведь он позволит и последний элемент отработать, и четный/не четный и т.п.

А>Это верно, код универсальнее, зато ключевые слова строже.

Ну, тут важен баланс. Я считаю, что если приемлемый результат достигается более универсальными методами, то это предпочтительный вариант.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.10 19:44
Оценка:
Здравствуйте, _nn_, Вы писали:

ИД>> то есть они делают совсем не то, что в питоне делают for-else (else-тело выполняется, если цикл не завершился break-ом) и while-else (выполняется, если цикл завершился по false == условие цикла), а выполняют else-тело, если основное тело не было вызвано ни разу. Все три варианта поведения мягко говоря не интуитивны. Как минимум, в документации должно быть отражено отличие от python.


__>Насчет break-ов действительно не подумал.

__>Доделать не сложно

Что-то я поглядел на все это (почитал о питоновской реализации, поспрашал питоновцев
Автор: VladD2
Дата: 26.07.10
и пришел к выводу, что в таком виде в каком эта фича есть в питоне нам (в Немерле) она не нужна.

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

Так что предлагаю или вовсе выкинуть это расширение из стандартной библиотеки, или оставить твой исходный вариант (но с ключевым словом otherwise).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: По поводу foreach / else
От: Ziaw Россия  
Дата: 27.07.10 08:05
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>В любом случае тоже самое можно реализовать сегодняшними средсвами практически не теряя в выразительности и скорости:

VD>
VD>foreach(item with index in lst)
VD>  if (index == 1)
VD>    Response.Write("Товар: <b>" + item.Name + "</b>")
VD>  else
VD>    Response.Write("Товар: " + item.Name);
VD>


Может тогда сделать несколько переменных с именем производным от переменной цикла?
foreach (item in lst with vars)
{
  if (itemIsFirst || itemIsLast)
    Response.Write("Товар: <b>" + item.Name + "</b>");
  else if (itemIndex % 2) 
    Response.Write("Товар: <i>" + item.Name + "</i>");
  else 
    Response.Write("Товар: " + item.Name);
}
Re[13]: По поводу foreach / else
От: _nn_ www.nemerleweb.com
Дата: 27.07.10 10:06
Оценка: 1 (1)
Здравствуйте, VladD2, Вы писали:

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


__>>Первоначальный вариант был неправильным как подмеченно здесь http://rsdn.ru/forum/nemerle/3892867.1.aspx
Автор: Иванков Дмитрий
Дата: 26.07.10
.

__>>Я начал исправлять и наткнулся на проблемы.

VD>Вот можно по подробнее об этих проблемах. А то я что-то не догоняю.


Поведение Python это вызов блока else всегда если не было break.

Сперва, спохватившись подумал, что надо менять как там, но все больше склоняюсь к оригинальному варианту как сейчас.
Т.е. otherwise вызывается если не было действия в цикле.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[14]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.07.10 14:47
Оценка: +1
Здравствуйте, _nn_, Вы писали:

__>Поведение Python это вызов блока else всегда если не было break.


__>Сперва, спохватившись подумал, что надо менять как там, но все больше склоняюсь к оригинальному варианту как сейчас.

__>Т.е. otherwise вызывается если не было действия в цикле.

В общем, мое мнение — питоновская реализация не понятна интуитивна, мало применима на практике, навязывает императивный стиль программирования и не соответствует ключевым словам else / otherwise (особенно последнему). Так что лично я против введения ее в немерловую библиотеку макросов.

Если хочешь можешь оставить свой первоначальный вариант, но с ключевым словом otherwise, в котором otherwise означает "вместо цикла" (вызванивается только тогда когда тело цикла не разу не выполнилось и не произошло исключения).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.07.10 15:50
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Может тогда сделать несколько переменных с именем производным от переменной цикла?

Z>
Z>foreach (item in lst with vars)
Z>{
Z>  if (itemIsFirst || itemIsLast)
Z>    Response.Write("Товар: <b>" + item.Name + "</b>");
Z>  else if (itemIndex % 2) 
Z>    Response.Write("Товар: <i>" + item.Name + "</i>");
Z>  else 
Z>    Response.Write("Товар: " + item.Name);
Z>}
Z>


Проще сделать несколько методов расширений которые бы работали с коллекций и индексом.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: По поводу foreach / else
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.07.10 00:14
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Сперва, спохватившись подумал, что надо менять как там, но все больше склоняюсь к оригинальному варианту как сейчас.

__>Т.е. otherwise вызывается если не было действия в цикле.

Согласен. Тогда остается только один вопрос. А нужен ли вообще этот else? Будет ли он реально использоваться?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.