Re: each kewword

new topic     » topic index » view thread      » older message » newer message

> >>I disagree. There's nothing wrong with the readability, maintainability,
> >>etc. of the second example. In fact, the first example could be *horribly*
> >>confusing, since the loop operation -- instead of being obvious -- is
> >>"hidden" in that little "each" keyword, lurking way out there on the end.
> >
> >Why would you want to see it as a loop operation ? Aren't such operations
> >hidden everywhere ? What if, printf accepted sequences as value-arguments,
> >in such way it would do the same ?
>
> ??? I don't entirely follow you. The loops are either "hidden" in
> pre-existing built-in functions, or within user-written routines. Either
> way, they follow Euphoria's existing rules for loops. The "each" keyword
> would require those rules to be quite drastically changed -- it would create
> loops out of statements that do not normally loop on their own.

Your point is the loop behaviour is hidden, and can therefor confuse you. My
point is a loop is just a level of 'interpretation'
and therefor, is not more confusing than loops on any of the other levels of
interpretation.

The following statements are all true.
    "In a loop, the same statement is executed one or more times."
"A statement can represent any small or large amount of action, time and
    code size".
"The statement s = s + 1 may be a single execution, a loop or even a
    recursive loop."
"The statement s = "!!!!!!!!!!" may be seen as a loop of the statement
    s[index] = '!' "
    "Loops can kill a dog.

Ok, so maybe not the last, but the others are all true. blink
Just try to get used to it. You don't have to see there is a loop, so who cares
if its hidden or not ?
You shouldn't even see it as a loop, but more like a datatype specification.

> >>In Euphoria 2.1, you can include get.e and code this:
> >>
> >>    s = get_bytes(fhandle, 10)
> >>
> >>Which is much cleaner than either of the above examples.
> >
> >In which way is the loop operation obvious now ?
>
> I trust you are not *seriously* suggesting that your "each" idea is in any
> way equivalent to a Euphoria function definition?

No, why would you think that ? You were the one that brought up get_bytes ().
My point is, whenever we make a function, we have a complex task, we wish to
'shorten' for sake of maintainability.
The same task wouldn't be complex at all, using the each keyword.

sequence s
s = repeat (0, 10)
each s = getc (fn)

> A pre-defined routine can *obviously* be expected to contain loop
> operations. Your "each" loops, again, would create loop operations out of
> statements that do *not* normally loop. This has great potential for
> confusing the programmer, since the loop is not visually obvious in the
> code.

Does it matter if the routine loops or if the end-programmer loops ?
And why can it lurk in a routine call, but not in a keyword ?
How much visually obvious is a routine call versus a keyword ? Seriously ?
And how visually obvious is the workings of the above code fragment and the
workings of the get_bytes routine, that counts more
than 10 lines to achieve the same thing.

> Additionally, in order to create these "each" loops, the Euphoria compiler
> would have to "reach back" to code that it has already processed in order to
> retroactively create these loops. To illustrate, I will use some of your
> original examples:
>
>  -- example 1
> printf (1, "The next number is %2d", {each s})
>
> When the compiler encounters the "each", it has already processed the
> "printf". Now, it has to "reach back" to insert loop instructions before the
> "printf" statement. This would certainly slow down the Euphoria compile
> step.

Off course not. What 'loop' statement would be inserted before the printf ()
statement in the execution stack. When it
encounters 'each s' .. then it will consider the amount of times it should jump
back, and initialize the counter. Secondly, do
we seriously know enough about the compile step to make any useful statement
about parsing speed. And thirdly parsing time
would IMHO not be increased that much, even if you're statement would be true. A
normal loop would take up as least an
equivalent amount. And fourthly, my program doesn't run during the compile step.

>  -- example 2
> puts (each fhandle_list, each text_image)
>
> Same problem as above, only now it has *two* loops it has to retroactively
> apply to "puts" (and it has to process them one at a time, too).
> Additionally, the statement itself is somewhat ambiguous. Do you want
> *every* text image to go to *every* file, or do you want the first text
> image to go to the first file, the second text image to go to the second
> file...?

    *every* ... *every*
Just read it like English and it says: "write/put each text_image to each
    file"
And because of this, order is much less important, than it would be when the
    first image with go to the first file and the
second to the second file .. etc. And yes, it has to process them one at a time.
The whole point, the loop is now the
responsibility of Euphoria, and it itself can choose to apply to the loop
statements either directly after the call, or
associate them with the variable-place-holders and have the loop brought back to
its smallest/most inner loop. Although, I must
admit, _this_ would be hard to implement. But even the difficulties of
implementation do not matter. Do you think Robert has an
easy time creating the sequence datatype ? Think not.

> >Also, don't you think it is interesting such a *routine* is (and had to
> >be) added to Euphoria Language? [get_bytes()]
>
> It didn't *have* to be included -- other programmers could easily have
> written something like it for themselves. It is included for convenience, so
> we don't have to re-invent the wheel.

They did actually. Robert was inspired by some one.

> The dilemma Robert faces with the standard include files is to give us all
> the library routines we'll need, but not to bloat everything to gargantuan
> size with hundreds of additional routines (which may never be used in a
> given program). IMHO, he has done pretty well in this regard.

    get_bytes () is just an Euphoria routine in file.e
    He could have added better IO routines as separate include files.
And as binary put & get, about 6 to 7 years ago, I suggested that a number
    of times.
    Eventually, I as an 14 year-old wrote EDOM1, one year later I wrote EDOM2.

> >(thankfully though, now just hope Robert optimizes making it fast
> >built-in function that uses blocks directly from the buffer)
>
> You can't turn *every* routine into a built-in just to gain a few percentage
> points of speed; otherwise, the bloating problems I mentioned above would
> affect EX.EXE and EXW.EXE. Euphoria is pretty darn fast in and of itself.

Well, considering the fact that Euphoria does its own caching (it does not
    need smartdisk, actually it surpasses it when
available) you would expect these routines to take a minimal _extra_ effort and
code size to the interpreter. I mean, don't you
think its silly that for really large files, people have written Int21 wrappers
to read whole blocks of data from a file at once
in half the time Euphoria code could do it, especially considering the fact that
super-de-luxe-fast caching routines were
already 'internally' available ? Why aren't the routines that getc (), gets ()
and puts () internally use wrapped ?

> >>It's far more obvious what's going on [with manually-coded "for" loops].
> >
> >No, it looks like a program made for the machine to understand, rather than
> >the human. It simple stupid steps, since you can't have the machine
> >effectively combine the concept of iterations with the concept of data.
>
> If you want a good example of "each" being integrated into Euphoria, check
> out David Cuny's preprocessor. It employs "with each" loops to achieve (in a
> more readable fashion) an effective combination of "the concept of
> iterations with the concept of data" (if I correctly understand what that
> means).

I know his PP, and I think its much more readable that the Euphoria equivalent,
nevertheless what he does, too, can easily be
done, using the 'each' keyword.

> An example:
>
> s = find_all(' ', string)
> with each pos in s do
>    printf(1, "Found a space at %d\n", pos)
> end with
>
> This clearly shows that a loop is taking place, and it doesn't require the
> programmer to deal with the sequence indexes. I like *this* a lot better
> than a "for" loop. However, this is *quite* a different "each" idea.

Not really, he has associated the action of the looping with the 'temporary'
variable name 'pos'.
Instead of 'pos' you could write 'each s'

> >>[Not to mention the serious logistical problems the interpreter would have
> >>to face, trying to figure out where the programmer wants the "each" loop
> to
> >>apply to within multiple nested operations. Are you trying to give Rob
> >>nightmares? :) ]
> >
> >Its only one statement, in other words, it doesn't really matter...
>
> ?!?!!?!?!!!?!?!!
>
> This shows how little you have really thought through your own idea. This
> "one statement" changes *all* the rules Euphoria plays by. Every existing
> operation in Euphoria will now have to be able to deal with the "each"
> keyword, since your design allows for it to appear just about anywhere. This
> is a *major* change to the whole language! To say "it doesn't really matter"
> is, charitably speaking, an astoundingly naive statement.

How can you constantly speak of 'implementation' difficulties, while you have no
clue how Euphoria is implemented.
All of the 'each' features, could _easily_ be handled by a preprocessor. In
other words, in theory, the run-time part of
Euphoria need not be altered, unless it wants to take advantage of the
optimizations possible using the 'each' keyword. So, how
can you speak of complex back-tracking, etc. ? What are you doing with the in
fact, simple parsing addition I am suggesting.

A statement is read from left to right. Whenever 'each' occurs, the statement is
wrapped by a loop, the variable following the
keyword is indexed by the loop's-counter. That's it.

And with the 'reply' .. suggestion for functions, it would be parsed in the same
easy manner:
Functions that use 'reply' rather than 'return' (using both is illegal) also
'allocate' space for a 'statement location
pointer', and after a reply statement has occurred, the local variables are not
yet de-allocated. The statement calling the
reply-function (looks up a flag), when finished, sents out the 'de-allocate'
local variables. Other than that, it just wraps the
statement with loops, just as what happens with sequences.

> >>You'll get an infinite loop, since "find(' ', s)" will always return 6,
> the
> >>position of the first space in s.
> >
> >Didn't it say " what if find () and match () worked this way ? "
> >In other words they don't currently. If the reply part together with the
> >each keyword would be native Euphoria code, the find () and match ()
> >could be made in such a way. Internally they would work as if they were
> >a function using the reply keyword.
> >Currently they don't.
>
> Are you suggesting that built-in functions should operate in subtly
> different ways depending on whether or not they have an "each" nearby?!?!
> Good Lord, what kind of horrific nightmares are you trying to inflict upon
> the Euphoria programmers of tomorrow?!

Tough words, lack of arguments. The built-in routines should not operate
different.
You haven't got a clue what I meant with the 'each' suggestion, do you ?
Built-in functions should completely behave like normal euphoria functions.
And thus a suggestion involving being able to 'reply' rather than 'return' in a
function, also involves built-in functions.
They should be able to return data this way as well ... duh....

> >Isn't the acceptance of a new term, its effectivity in expression ?
> >Something clearly applying to 'each'.
>
> Not clear at all. Your "each" idea would clearly steepen the Euphoria
> learning curve, introducing whole rafts of exceptions (and exceptions to the
> exceptions) into Euphoria's current scheme of things -- just as you yourself
> have demonstrated with your ideas regarding find() and match().

What exceptions, what learning curve ? Only because you're too ... (saying this
would sound rude) does not mean the concept it
too difficult, or more difficult. It does not include any exceptions. Its very
consistent.
No 'subtle' different ways of working. How dare you criticize my idea, without
any lack of insight or interest into what I meant
?

> >...And like the 'each' keyword, you don't have to use it, if you don't want
> to.
>
> Can we *please* stop using this argument for every weird thing people want
> to shoehorn into Euphoria? Unlike most major languages, Euphoria is *not* a
> hodge-podge of almost-compatible ideas patched very badly together. Rather,
> Euphoria has a clear conceptual unity running through almost every part of
> it -- which, incidentally, is what helps make it so easy to learn. Adding
> this "each" construct to the language would require *major* changes
> throughout the entire compiler/interpreter, which could adversely affect
> *all* Euphoria code, whether people use "each" or not.  Additionally,
> learning how Euphoria works could potentially become more difficult, since
> exceptional conditions involving "each" must be taken into account.

There are a total of 2 lies in the above statements.
1) It would not require major changes throughout the entire compiler/interpreter
2) There are no exceptional conditions involving "each" , so they don't have to
be taken into account.

> This is not to discourage you, Ralf, from coming up with new and creative
> ideas for Euphoria. Rather, I *encourage* you to clarify your thoughts on
> this idea, to clearly show how and where "each" could and could not be used,
> and to describe exactly how Euphoria's current behavior would have to
> change. The acceptance of a new construct relies on its being clearly
> defined, and on taking into account its effects on the programming language
> involved. A more clearly defined set of rules for your idea may resolve many
> of the issues I have mentioned here.

So, I will re-explain the same original idea again:

"A programmer uses a computer"
"Each programmer uses a computer"

First of all, for better explanations of the concept. try searching for the
programming language 'ICON'. Its a messy language,
but this feature is quite unique and strong.

The each keyword means: rerun the statement using every element of the following
variable.

s = {"Hello, world", "How are you ?'}
puts (1, each s)

Will translate into:

for index = 1 to length (s) do
    puts (1, s[index])
end for

Or consider this example:

puts (1, "The tables of three are:\n")
s = {1,2,3}
print (1, each s * each s)

Will translate in 2 steps into:

puts (1, "The tables of three are:\n")
s = {1,2,3}
for indexA = 1 to length(s) do
    print (1, s[indexA] * each s)
end for

And eventually into:

puts (1, "The tables of three are:\n")
s = {1,2,3}
for indexA = 1 to length(s) do
    for indexB = 1 to length(s) do
        print (1, s[indexA] * s[indexB])
   end for
end for


Using David's syntax you would have written it like:

    puts (1, "The tables of three are:")
    s = {1,2,3}
    for each itemA in s do
        for each itemB in s do
            print (1, itemA * itemB)
        end for
    end for

I am personally in favor of having 'both' syntaxes.
David's is more flexible (you could use the items more than once), but the
'each' keyword is much more 'expressive'.
However, be clear there is one tiny difference. In this situation 'each' is used
at the 'right' side only.

About the assignment operator...
In the above the number of iterations of the statement is obvious: 3 * 3.
But what if the statement read:

each z = each s * each s

Well, in this case its not:
length(z) * length(s) * length(s)

With assignments, the left-side determines the amount of iterations, but stops
if the right side is unable to deliver new
values.

sequence s, z, g
s = {1,2,3}
z = {4,5,6}
g = repeat (0, 27)

each g = each s * each z
-- only the first 9 elements of g are set.

This translates into:

integer s_count, z_count
s_count = 1 z_count = 1
for index = 1 to length(g) do
    g[index] = s[s_count] * z[z_count]
    s_count = s_count + 1
    if s_count > length(s) then
        z_count = z_count + 1
        s_count = 1
    end if
    if z_count > length(z) then
        exit
    end if
end for

As you noticed, because of concurrent running loops, I manually constructed the
s and z loop.

But sequences was not really the, IMHO, strongest points of the 'each'
suggestion. Its in the reply functions.
In this example, I have used another name to declare this function. This need
not to be, since you can not have both a reply and
a return statement in one function, the interpreter could distinct the two
different types. But those are just cosmetic choices.

stream find (object x, sequence s)
    for index = 1 to length(s) do
        if equal (x, s) then
            reply index
        end if
    end for
end stream

if find (' ', "Does this contain spaces ?") then
    puts (1, "Find works as it used to do!")
end if

sequence s
s = each find (' ', "How many spaces does this contain ?")

But streams are even more interesting, when the 'each' keyword is not used upon
_them_

sequence s
s = repeat (0, 5)
each s = each find (' ', "How many spaces does this contain ?")
--  s now contains the first 5 positions where a space was found. (there were a
total of 6)

Compare this to the same with a sequence:

sequence s, z
z = each find (' ', "How many spaces does this contain ?")
s = repeat (0, 5)

each s = each z
-- s now contains the first 5 elements of z.

There is only _one_ difference between a stream and a sequence.
And that happens, when we're not using the 'each' keyword.

z = {1,2,3}
print (1, z)
-- Will display: {1,2,3}
print (1, find (' ', "   "))
-- Will display: 1

By default, streams will only reply the first value. (by default... i.e..
without the 'each' keyword)

Streams could also be available through a david-like interface:
(so you can keep the loop visually obvious or whatever)

for each pos from find (' ',"   ") do
    print (1, pos)
end for

A thing that would complement 'each' a lot would be 'all' though.

s = {1,2,3}
print (1, all s * all s)
-- displays:
    -- 1
    -- 4
    -- 9

I don't think I need to explain 'all' in the light of 'each' do I ? Quite
obvious..

s = {1,2,3}
print (1, all s * each s * each s)
-- displays a total of 9 numbers.

Ralf

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu