last iteration of a for loop

Discussion in 'Perl Misc' started by hymie!, Feb 26, 2014.

  1. hymie!

    gamo Guest

    El 27/02/14 12:11, Ted Zlatanov escribió:

    I miss in this discusion a solution using when/default.
    Can not be as efficient as using if?
     
    gamo, Feb 28, 2014
    #21
    1. Advertisements

  2. As contorted because it is just another way of putting
    some code into the loop body which simply doesn't belong in there,
    hence, execution of it has to be disabled by 'hitting the loop on the
    head with a blunt instrument' and as inefficient because some unchanging
    fact which was known at the time the code was written needs to be
    'reguessed' with a suitable heuristic at run time. It is also as
    invasive because it can only work when it is known if the current
    element is the last element.

    A general workaround is possible based on special-casing the first
    element of the "set of things we're iterating over" because it is always
    known if the current element is the first element. But this would still
    require support at the language level for it to be sanely applicable to
    all kinds of supported loops.

    Something Wikipedia calls 'loop with test in the middle' can also be
    built in Perl:

    ----------
    my $line;

    defined($line = <>) and do {
    LOOP: {
    print($line);
    $line = <> // last;
    print("---\n");
    redo;
    }
    };
     
    Rainer Weikusat, Feb 28, 2014
    #22
    1. Advertisements

  3. It doesn't need to 'know' that, all which is necessary is - for each
    iteration - execute the ordinary loop body before the condition is
    evaluated and the 'again' ('onrepeat' seems a better name to me) block
    after evaluating the condition resulted in the descision that another
    iteration will be done. Some programming languages support
    condition-less loops, eg,

    http://www.postgresql.org/docs/8.4/...uctures.html#PLPGSQL-CONTROL-STRUCTURES-LOOPS

    Perl loop control statements work with bare blocks, hence, unconditional
    loop can be implemented as

    {
    # some code here
    redo;
    }

    and this enables putting a test for loop termination anywhere in between
    which provides the desired semantics. But this works only for loops
    with an explicit condition, not for 'loop over the members of the set'
    loops and it requires testing the condition once before entering the
    block for loops which start with testing the condition. Also, this is
    bound to confuse people who expect that loops 'look' like loops and
    don't hide in bare blocks and suddenly jump at the without warning.

    Something which works exactly like a continue block, only that the code
    would be executed immediately after evaluating the condition instead of
    befor doing so would be a much nicer alternative, not the least because
    it would mean a description of the intent of the code could be provided
    to the compiler which would then utilize a suitable way of achieving
    that instead of one the the numerous ways to 'interfere creatively' with
    the control-flow of an ordinary loop which were presented in this
    thread.
     
    Rainer Weikusat, Mar 2, 2014
    #23
  4. hymie!

    Ted Zlatanov Guest

    h> So I've got a for loop. It's doing some printing, and at the end of
    h> what it prints, it prints a separator line likeh> Is there an easy way that I can tell my loop "don't print the separator
    h> after the last iteration"?
    BM> If you're going to build an array anyway, you might as well just use
    BM> join. (If you want more general 'joining', see List::Util::reduce.)

    join() is sometimes less efficient because it builds a temporary string
    just for printing it out. But my approach often requires a temporary
    array, which is sometimes less expensive, sometimes more than join()...
    It depends on the task, really.

    A big advantage of using a temporary array is that it can be augmented
    during the loop. I've build simple crawlers (web and data structure)
    that way, pushing things at both ends of @list. A fire-and-forget
    folding (reducing) function is tempting but often not the right way for
    these situations.

    Regarding List::Util::reduce, it also does not tell you that you're at
    the last iteration. That really is a useful piece of knowledge in many
    cases.

    Ted
     
    Ted Zlatanov, Mar 3, 2014
    #24
  5. hymie!

    Ted Zlatanov Guest

    g> I miss in this discusion a solution using when/default.
    g> Can not be as efficient as using if?

    When you have to use older Perls a lot, like I do, you tend to avoid
    when/default. It's not bad, just annoying when I have to rewrite the
    code and deal with complaints, so I often stick to the oldest common
    denominator (OCD) :)

    Specifically in this case, the efficiency is about the same and I was
    writing an example that can be copy-and-pasted easily, but normally I'd
    store the check result instead of recalculating it twice.

    Ted
     
    Ted Zlatanov, Mar 3, 2014
    #25
  6. hymie!

    Tim McDaniel Guest

    Isn't it also experimental and complicated?
     
    Tim McDaniel, Mar 3, 2014
    #26
  7. hymie!

    Ted Zlatanov Guest

    On Mon, 3 Mar 2014 18:14:56 +0000 (UTC) (Tim McDaniel) wrote:


    TM> Isn't it also experimental and complicated?

    I'm not against it, but personally prefer the semantics of Lisp's cond
    or C/C++/Java's switch. Recently I've found the `pcase' macro in Emacs
    Lisp, which "performs ML-style pattern matching," interesting as well.

    I think at least half of the fun in programming is trying new toys :)

    Ted
     
    Ted Zlatanov, Mar 3, 2014
    #27
  8. The actual text says

    Smart match, added in v5.10.0 and significantly revised in
    v5.10.1, has been a regular point of complaint. Although there
    are a number of ways in which it is useful, it has also proven
    problematic and confusing for both users and implementors of
    Perl. There have been a number of proposals on how to best
    address the problem. It is clear that smartmatch is almost
    certainly either going to change or go away in the
    future. Relying on its current behavior is not recommended.

    Warnings will now be issued when the parser sees ~~ , given , or
    when.

    [...]

    Consider, though, replacing the use of these features, as they
    may change behavior again before becoming stable.

    http://perldoc.perl.org/5.18.0/perldelta.html#The-smartmatch-family-of-features-are-now-experimental

    AIUI, this does not state that the idea to introduce a real switch/ case
    statement into Perl was 'a rather bad one'[*] but that the DWIM-approach
    behind 'smart matching' which has been marked as experimental turned out
    to be "Damn Warren's Infernal Machine" for any who wasn't Warren, as
    this kind of things are wont to go, IOW, that a lot of people 'meant'
    smart matching to do something completely different than what its
    author(s) happened to consider "the only sensible proposition" for each
    given case.

    Considering this, I think that it is likely that Perl will retain the
    given/ when/ default part, although with different and possibly entirely
    'unsmart' matching semantics, eg, use equality instead, and probably,
    with some way to request for 'set matches', ie, consider a condition as
    true when the given value is a member of somehow specified list. OTOH,
    the ~~-operator might will disappear entirely if it turns out to be
    impossible to agree upon sensible semantics (and I certainly wouldn't
    mind that as I found 'smart matching' rather dumb on several occasions).

    [*] This doesn't necessarily mean that the focus isn't really about the
    sentiments of people who go ballistic once the encounter something which
    isn't an if-elsif-elsif-else cascade, just that the text doesn't seem to
    state this to me.
     
    Rainer Weikusat, Mar 4, 2014
    #28
  9. hymie!

    Kaz Kylheku Guest

    Smart feature sometimes turn out not-so-smart.

    A few days ago I took out the "smart quote" out of TXR Lisp.

    It breaks backward compatibility, but damn backward compatibility.

    This was an experiment in using a single quote character in the read
    syntax for both regular quotes and quasiquotes.

    So '(a b c) is a quote, but '(a b ,c) was a quasiquote.
    What prompted me to experiment in that direction was that the backquote
    character was already taken for quasiliterals.

    This almost worked fine. Under the hood, the parser would walk the template,
    and decide "do I generate the quote operator for this, or the qquote macro?"
    There were some hacks like treating ,' unconditionally as a spliced quote.

    In the end, the deal-breaker was that the print syntax hid the difference
    between the two operators, mapping them back to the apostrophe. Combined with
    the several more hacks I had to put in, it made for a bad recipe: you have an
    object which prints out as ''(a '(,',a)) or whatever and don't know what exact
    structure the quotes stand for; and, more importantly, is it the same structure
    that would result if you parsed that notation as a string?

    So, the right thing is to perform a hack-ectomy. The backquote operator is
    now the caret sign, and quote is just quote.

    If a feature is bad, throw it out, ASAP. Don't let another day go by with more
    programs depending on it.

    Don't be like Dennis Ritchie: oh we can't fix the precedence of the bitwise &
    operator now that we have &&, because there is a whopping 600 kilobytes of
    existing C code already.
     
    Kaz Kylheku, Mar 4, 2014
    #29
  10. If in doubt, an invisible 'Greg KH' who has no problems with claiming to
    be "The Greatest Programmer On Earth" and considering switch-statements
    so incomprehensible that they have to be replaced at the same time and
    any other dedicated member of the software section of the "There's
    nothing worthwhile of being stated which can't be expressed clearly by
    a string of differently accentuated 'fucks'"-tribe.

    [...]
    I was writing about 'equality' and possibly, some notion of set
    matches. I didn't include regexes because these can already be matched
    against $_ without writing the '$_ =~'-part every time. I was also being
    intentionally vague on 'set matches' because this was supposed to
    include the possibility of something with a much more limited scope than
    the 14 different set matches documented for perl 5.10.1 smart matching.

    I'll address the 'equality' issue below.
    That would hardly be worthwhile.

    [...]
    Trying to be so ueber-smart that the final result is nothing because the
    problem invariably diffuses into a cloud of nebolous opinions which all
    have something going for and against them it isn't particular smart in
    the end. "Do something less ambitious for now and leave the complicated
    stuff for the future" is IMHO a better approach. Eg, a C
    switch-statement requires all cases to be integer constants. That's
    already useful when dealing with functions returning some discrete
    values and possibly, a default case, eg, fork or <=> or anything which
    returns 'magic numbers' to indicate different things. 'Equality' than
    becomes == and if this doesn't do what is desired, another construct has
    to be used. Going one step further, one could allow 'string literals'
    (including interpolation) as well. 'Equality' than mean 'use == if it is
    an integer constant and eq otherwise'. Additionally dealing with literal
    regexes shouldn't be a big problem.

    This would cover almost everything I've been using given/when for so
    far and would still go beyond what is provided by the most 'current'
    version of Java. I've actually used functions a la

    sub eql($)
    {
    return $_ == $_[0];
    }

    or

    sub equal($)
    {
    return $_ eq $_[0];
    }

    in the past in 'switch statements implemented as for loop' to avoid
    repeating the '$_' (of course, I want to use that, that's why I wrote
    for (something) {} in the first place) and the same comparison operator
    every time.

    Another simplistic addition would be to allow 'range operator
    statements' in order to match a sequence of integers or literal strings.
    AFAIK, with-statemens have existed in Pascal since "the dawn of times"
    (relative to the age of VB, that is) ...
     
    Rainer Weikusat, Mar 4, 2014
    #30
  11. Practically, this will often be

    given (fork()) {
    when (undef) {
    }

    when (0) {
    }
    }

    ie, the return value doesn't have to be stored in a variable if it isn't
    ever going to be used except for determining the result of the
    fork. Even if that becomes

    given ($pid = fork() {
    when (undef) {
    }

    when (0) {
    }
    }

    it is still immediately evident that there's one operation which
    produces a result and different code blocks dealing with several,
    possible outcomes. This may also be the case for an if - elsif - else
    cascade but it need not be: Only the last two branches are necessarily
    related to each other, any remaining ones could be completely
    independent. And there are no keywords chaining subsequent blocks
    together because the 'else' is implied in the construct.

    [...]
    Judging from performing some tests with Perl constants, this seems to be
    a problem which could be solved. The main issue here seem to be 'string
    constants' whose values can be interpreted as valid
    numbers. Distinguishing these from numerical constants which acquired a
    string representation because of the inner workings of Perl would
    require something like a set of 'originally, I was a ...' flags.
     
    Rainer Weikusat, Mar 5, 2014
    #31
  12. Keeping additional meta-information about 'Perl constants' supposed to
    be used solely while compiling wouldn't necessarily make anything
    'larger' at run time.
    I don't disagree with statement. What I was writing about was to enable
    the Perl compiler to select 'an operator' for a comparison at
    compile-time, based on the known type of one of its arguments.That would
    be a somewhat more feature-full equivalent to 'multiway conditionals' in
    other languages.

    And this is certainly perfectly doable.
     
    Rainer Weikusat, Mar 5, 2014
    #32
  13. A 'constant' PVIV or PVNV has two length fields like any other
    'PV-thing' and considering that it's string representation won't grow,
    one of them isn't really needed. It also has a reference count which
    isn't really needed (or, more correctly, most bits of which aren't ever
    going to be used). It's very likely that there are more unused bits in
    this memory area, malloc metainformation would come to mind here. Not
    caching 'type conversion results' in the original object itself on the
    grounds that they'll be rarely - if ever - useful for 'typical cases'
    might also be a viable option.

    This is an engineering problem and it can certainly be solved in the
    sense of meeting any more specific technical requirements than "don't do
    anything because that would cause an effect".
    That would be 'for the sake of a standard feature of every high-level
    programming language I've used so far which Perl unfortunately
    traditionally lacks' (or 'used to lack until 2007 and may again lack "in
    the future"').
    'An operator which is polymorphic on the types of its operands' would be
    a multi-method (or 'a generic function' in CLOS terminology) which can
    be used at run time and which inspects the types of its actual operands
    for dispatching whenever it is invoked. Making the compiler infer an
    existing non-polymorphic operator based on the 'static' type of one
    operand is something rather different from that.
     
    Rainer Weikusat, Mar 6, 2014
    #33
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.