February 21, 2002
On Wed, 20 Feb 2002 20:51:16 -0800, Russell Borogove <kaleja@estarcion.com> wrote:
> Well, if you were 1-based, it would be natural to be
> both-ends-inclusive in all cases, because array.length
> would be the index of the last element as well as its
> size. I am not sure if this was what Mr. Bochert was
> getting at or not.
> 
Array slicing is the same as case ranges:
array[2..4]   // second, third, and fourth elements
case [2..4]  // cases 2,3,4
Both 'array' and 'case' include the end elements as the text would indicate.
(The syntax includes the ends ---- so should the semantics.)

> You'd have to get used to starting from one,
When I first ran into 1-based arrays (in Euphoria)  I, a life-long
C programmer, was extremely suspicious to say the least.
One day's use convinced me.

> and you'd
> want to use <= instead of < in the idiomatic for-loop:
> 
> for (i = 1; i <= array.length; i++)
> {
>     ...
> }
> 
Makes more sense doesn't it -- the last element done is the one equal to the array length. It just looks more like the lfirst and ast elements are included in the loop.

Karl Bochert



February 21, 2002
On Thu, 21 Feb 2002 00:36:41 -0800, "Sean L. Palmer" <spalmer@iname.com> wrote:
> This would be bad from a performance standpoint, as the compiler would have
> to sneak in a hidden "minus one" when indexing into an array.
> sometimes it could do this offset at compile time, if the array address is
> known at compile time.
This is a very small performance hit. In most cases of indexing from a variable,
the 'offset' would already be built into the variable. In cases where the index
is computed,  there is usually a place to modify a constant as opposed to
doing an add.


> Or the BASIC approach could be used, and the
> language allocate one extra entry in each array to humor those careless C
> programmers who think 0 is a valid index.  ;)
> 
Probably not a good idea, given that the array elements could be very large.
Could a 'zero'th element' hold something else of interest?
The type?
The size of the elements?

Karl Bochert




February 21, 2002
"Karl Bochert" <kbochert@ix.netcom.com> wrote in message news:1104_1014316439@bose...

> This is a very small performance hit. In most cases of indexing from a
variable,
> the 'offset' would already be built into the variable. In cases where the
index
> is computed,  there is usually a place to modify a constant as opposed to doing an add.

I don't see what you can do when index is a variable, like in foo[i]. Either way you have to increase it by the array base - which is not only slower, but requires a place for temporary, probably a register... After all you can always do foo[base+i] if it's really needed.

> Probably not a good idea, given that the array elements could be very
large.
> Could a 'zero'th element' hold something else of interest? The type?

Type of what?

> The size of the elements?

It's (*foo).size


February 21, 2002
"Karl Bochert" <kbochert@ix.netcom.com> wrote in message news:1103_1014316261@bose...

> Array slicing is the same as case ranges:
> array[2..4]   // second, third, and fourth elements

Arrays are _zero-based_. a[2] is actually the _third_ element. Slicing should be no different!

As for the end-inclusive thing... this is a matter of personal taste, I believe. I like it as it is implemented now by Walter. Most people here seem to dislike it though (but have you _tried_ it?)...

> case [2..4]  // cases 2,3,4

Could be. Just don't use .. to avoid confusion, some keyword would be better.

> When I first ran into 1-based arrays (in Euphoria)  I, a life-long
> C programmer, was extremely suspicious to say the least.
> One day's use convinced me.

When I (3-year BASIC user, then 1-year Pascal user) ran into 0-based arrays
in C++, I found out that they are actually easier to use. Even now,
in my BASIC programs, I declare arrays zero-based. BTW remember that
VB.NET does so as well?

Also, Euphoria is an interpreter - so that impact on perfomance isn't really important there.

> Makes more sense doesn't it -- the last element done is the one equal to the array length. It just looks more like the lfirst and ast elements are included in the loop.

I don't see much difference, really. The most important thing is that you can tell the number of iterations easily:

    for (int i = 0; i < 10; i++)      for (int i = 1; i <= 10; i++)

Only the first syntax reminds us that arrays are actually 0-based (when used to iterate through an array), while the second would remind of 1-based arrays if they were there...


February 21, 2002
Goto should not be used for fallthroughs.  It is too general a construct and will result in spaghetti like references in larger case statements.

Further, as I said earlier, goto limits the ability of the compiler to
perform optimizations.  Typically case
statements are implmented as a series of nested conditional jumps.  This is
highly inefficient both in terms of execution and code size.  Often it is
possible to replace these nested tests and jumps with a more compact and
efficient loop and table structure.

When defined in a manner similar to that below, one dispatch function can be
used to dispatch for
all such optimizations.

       omov esi,jtab
        mov cx,[esi-2]
 foo: cmp eax,[esi]
        je     foo1
        add  esi,8
        dec  cx
        jne   foo
        ret

foo1: jmp [esi+4]

         dw  5
jtab:  ddq val1,addr1
         ddq val2,addr2
         ddq val3,addr3
         ddq val4,addr4
         ddq val5,addr5


Sean L. Palmer <spalmer@iname.com> wrote in message news:a4o7vb$sam$1@digitaldaemon.com...
> Please, no!!  Let's use break and continue just for loops.  Otherwise it gets confusing.  I'd rather just use goto to implement fallthrough.  Or
goto
> case.  A new "fallthru" keyword would work as well... so long as Walter doesn't mind cluttering up the language with lots of keywords.  ;)



February 22, 2002
>>My suggestion of syntax:
>>
>>    select (n)
>>    {
>>        case (0)
>>            foo();
>>        case (1, 3, 7)
>>        {
>>            int m = foo(n);
>>            bar(n);
>>        }
>>        case (2, 4 .. 6, 9)
>>            bar(n);
>>        default
>>            throw new Error;
>>    }
>>
>>This should deal with most switch() problems:
>>
>>    - no more break; only one case-block gets executed. Block statement
>>      is required if there are more then one statement in case (just
>>      like all other D constructs)
>>    - easy to check for several possible values and/or range

I don't personally mind the c-style switch statement.  The fall through
behavior can be extremely handy at times, and i haven't personally had
much problem with forgetting the break when it's necessary.
If something has to be changed though, why not leave case and default as they are and add something like and "else:"

switch(x)
{
  case 1:
    .....
    //no break
  case 2:
    .....
    //no break
  default:
    .....
  else:
    .....
}

Here the default block would always be called and the else block would only
be called if (x != 1) && (x != 2).  This would retain the C-flavored syntax of D, give C guys what they are used to, and give BASIC guys an alternative to the "fall through" behavior (the compiler could even eliminate the fall through for real if the default code block was absent).

P.S.  I wouldn't be opposed to enumerations (case 1,2,3:) but ranges (case 1..3:)?  There is a reason for the if statement.  Part of the beauty of D is that everything is simple and straightforward.  I vote for leaving it that way.

February 22, 2002
The code generator can easily tell that the only exit from a block is to another block, and move that block's code just before the one it goto's to, and eliminate the goto completely.  This doesn't go away if you hide it behind voodoo "break" syntax either... you still can get cases where more than one case wants to fallthrough to another case.  C doesn't handle that any better.  To someone unfamiliar with C, the lexical adjacency doesn't help them understand what's going on any better.  At least the goto is fairly obvious to a newbie.  Any modern optimizing compiler won't have much trouble with it, although a homegrown compiler may generate suboptimal code for it (it's gonna have worse problems than this though)

You're making the mistaken assumption that the "normal" thing people do with switch is fallthrough, while in fact quite the opposite is true.  Making fallthrough easier at the expense of "normal" code is bad.  Therefore "no fallthrough" should be the default and some other method should be used for fallthrough.

Someone already suggested "goto case" and "fallthrough".  Either one is fine.  Just don't use continue or break.

Sean

"d" <s_nudds@hotmail.com> wrote in message news:a53ql5$2hk1$1@digitaldaemon.com...
> Goto should not be used for fallthroughs.  It is too general a construct
and
> will result in spaghetti like references in larger case statements.
>
> Further, as I said earlier, goto limits the ability of the compiler to
> perform optimizations.  Typically case
> statements are implmented as a series of nested conditional jumps.  This
is
> highly inefficient both in terms of execution and code size.  Often it is possible to replace these nested tests and jumps with a more compact and efficient loop and table structure.
>
> When defined in a manner similar to that below, one dispatch function can
be
> used to dispatch for
> all such optimizations.
>
>        omov esi,jtab
>         mov cx,[esi-2]
>  foo: cmp eax,[esi]
>         je     foo1
>         add  esi,8
>         dec  cx
>         jne   foo
>         ret
>
> foo1: jmp [esi+4]
>
>          dw  5
> jtab:  ddq val1,addr1
>          ddq val2,addr2
>          ddq val3,addr3
>          ddq val4,addr4
>          ddq val5,addr5
>
>
> Sean L. Palmer <spalmer@iname.com> wrote in message news:a4o7vb$sam$1@digitaldaemon.com...
> > Please, no!!  Let's use break and continue just for loops.  Otherwise it gets confusing.  I'd rather just use goto to implement fallthrough.  Or
> goto
> > case.  A new "fallthru" keyword would work as well... so long as Walter doesn't mind cluttering up the language with lots of keywords.  ;)



February 22, 2002
Try rewriting this as a switch statement (without ranges) sometime:

char c;
if (c >= 'A' && c <= 'Z')
{
  printf("uppercase");
}
else if (c >= 'a' && c <= 'z')
{
  printf("lowercase");
}

Fingers tired yet?

Even though in this case a 256-byte table wouldn't be that bad of a way to generate the code, if you're only interested in speed.

Sometimes ranges can be a big time saver for the programmer.  Also easier to maintain if used properly.

Sean


"Jon Allen" <jallen@minotstateu.edu> wrote in message news:3C758B5B.8020307@minotstateu.edu...
> >>My suggestion of syntax:
> >>
> >>    select (n)
> >>    {
> >>        case (0)
> >>            foo();
> >>        case (1, 3, 7)
> >>        {
> >>            int m = foo(n);
> >>            bar(n);
> >>        }
> >>        case (2, 4 .. 6, 9)
> >>            bar(n);
> >>        default
> >>            throw new Error;
> >>    }
> >>
> >>This should deal with most switch() problems:
> >>
> >>    - no more break; only one case-block gets executed. Block statement
> >>      is required if there are more then one statement in case (just
> >>      like all other D constructs)
> >>    - easy to check for several possible values and/or range
>
> I don't personally mind the c-style switch statement.  The fall through
> behavior can be extremely handy at times, and i haven't personally had
> much problem with forgetting the break when it's necessary.
> If something has to be changed though, why not leave case and default as
> they are and add something like and "else:"
>
> switch(x)
> {
>    case 1:
>      .....
>      //no break
>    case 2:
>      .....
>      //no break
>    default:
>      .....
>    else:
>      .....
> }
>
> Here the default block would always be called and the else block would
only
> be called if (x != 1) && (x != 2).  This would retain the C-flavored
> syntax of D, give C guys what they are used to, and give BASIC guys an
> alternative to the "fall through" behavior (the compiler could even
> eliminate the fall through for real if the default code block was absent).
>
> P.S.  I wouldn't be opposed to enumerations (case 1,2,3:) but ranges (case 1..3:)?  There is a reason for the if statement.  Part of the beauty of D is that everything is simple and straightforward.  I vote for leaving it that way.
>


February 22, 2002
"Sean L. Palmer" <spalmer@iname.com> wrote in message news:a552t1$1g0$1@digitaldaemon.com...

> Someone already suggested "goto case" and "fallthrough".  Either one is fine.  Just don't use continue or break.

What about "next"?

select (foo)
{
    case (1)
    {
        ...
        next;    // fallthru
    }
    case (2)
    {
        ...
        next;    // fallthru
    }
    case (3)
    {
        ...      // NO fallthru
    }
}


February 22, 2002
"Sean L. Palmer" <spalmer@iname.com> wrote in message news:a552t1$1g0$1@digitaldaemon.com...

> Someone already suggested "goto case" and "fallthrough".  Either one is fine.  Just don't use continue or break.

What about "next"?

select (foo)
{
    case (1)
    {
        ...
        next;    // fallthru
    }
    case (2)
    {
        ...
        next;    // fallthru
    }
    case (3)
    {
        ...      // NO fallthru
    }
}