1. Problems with structures

Many of the responses to my original post are still overlooking some
fundamental problems. I'm going to use more examples here, to help clarify
my points. I warn you, this is *long*. But the detail is necessary.

I agree that something *like* structures is needed and would be very useful
in Euphoria, for very much the same reasons they're useful in other
languages. An example from QuickBasic:

TYPE Card
    Suit AS STRING * 9
    Value AS INTEGER
END TYPE

DIM Deck(1 TO 52) AS Card
Deck(1).Suit = "Club"
Deck(1).Value = 2
PRINT Deck(1).Suit, Deck(1).Value

As you can see, it's very easy to understand what's going on here. You have
a deck of 52 cards, identified here by suit and value. You don't have to
define constants to use as subscripts (i.e. Suit = 1, Value = 2) -- you can
give the individual portions field names to uniquely identify them. Plus,
the compiler will *always* know if a field reference is valid or not, and
can tell you right away if you've made a mistake. If I were to try this...

DIM Hand(1 TO 7) AS STRING * 9
Hand(1).Suit = "Spade"

..the compiler would immediately flag it as an error -- the "Hand" array is
not defined to contain "Card"-type data, so the ".Suit" reference has no
meaning here. The same goes for all the other languages containing
structures -- since every data element's type *must* be defined beforehand,
the compiler can know instantly if a field reference is valid or not.

Now, let's look at a Euphoria-style example, based on the above. [Note: in
all my examples, I will use "?" to indicate general screen output, rather
than the specific "?" statement.]

 -- we'll assume the string_9() type is already defined as a
maximum-length-9 sequence of integer values

structure Card
   string_9 Suit
   integer Value
end structure

sequence Deck of Card

 -- we'll ignore for the moment the problem of initialization...

Deck[1].Suit = "Club"
Deck[1].Value = 2
? Deck[1]

This seems just fine, doesn't it? Just throw in structure definitions and
"of" statements and you're all set! It sure *seems* to simplify things --
and if you don't like it, just don't use structures! That's pretty much the
pro-structure viewpoint, and it seems quite reasonable at first glance.

However, these examples (and most others I've seen) are deeply flawed,
because they are all based on examples from other languages that *only* have
rigid definitions for variables. They don't deal with the fundamentally
different way that Euphoria treats its variables.

First of all, look at the apparently harmless syntax of "sequence Deck of
Card". Heck, it almost reads like English, doesn't it? However, this now
marks a *major* departure for the definition of objects. Before, the only
restriction on an object was its type -- be it sequence, integer,
user-defined types, whatever. With this new syntax, however, an object can
be *doubly* restricted -- both in type and structure. Imagine if someone
tried to do this:

string_9 Hand of Card

What is the interpreter to do? Yes, the "string_9" type conflicts with the
"Card" structure, but the interpreter won't know that until "Hand" is
initialized -- at *runtime*. This can cause much confusion, since a
definition like this won't cause a "compile" error. I suppose we could
restrict the "of" clause to be used only with "sequence" declarations, but
then what if we have our own user-defined sequence types that we *want* to
use with "of"? Like this:

my_sequence Hand of Card

There will most likely be occasions where we would like to do this. But
there's no way for Euphoria to know if there's a conflict between type and
structure until the program actually runs, and the first value is assigned
to "Hand".

In any event, we would have two *very* different ways of restricting object
values. This does not strike me as being "elegant".


Secondly, examples such as these don't deal adequately with generic Euphoria
objects. Most of the structure ideas I've seen show how we could define and
use the structures, but don't really examine how *normal* Euphoria would
work with them. What if I try this:

object one_card
one_card = Deck[1]
? one_card.Suit
? one_card.Value

It seems simple enough at first glance -- the object "one_card" is assigned
the value from "Deck[1]", which is in "Card" format. So naturally the field
references would make sense. But how does the Euphoria "compiler" know for
sure what's in "one_card"? How does it know that "one_card.Suit" is a valid
field reference? After all, "one_card" is a generic object. There's no
guarantee that it will *always* contain "Card"-structured data. In theory, I
suppose the Euphoria "compiler" could try to get really clever  -- it knows
that "Deck[1]" contains "Card"-structured data, so it "allows" the field
references to be attached to the object "one_card" in this particular case.
In practice, however, this would be a *nightmare* to implement, especially
if the value is passed back via a function:

function get_card()
   return Deck[1]
end function

object one_card
one_card = get_card()
? one_card.Suit
? one_card.Value

The Euphoria "compiler" would have to know that function get_card() always
returns a "Card"-structured object! Now imagine hundreds of structure
definitions, and thousands of functions all returning different structures
-- poor old Euphoria would have to chase down all this extra information at
"compile" time just so it knows if the field references are valid. This is
clearly ridiculous. "Compile"-time field-reference checks in Euphoria -- as
depicted here -- are impossible.

This means that field references would *only* be resolvable at runtime. This
would be a major step backwards -- normally Euphoria catches all sorts of
things other languages force you to hunt down for yourself, but in this case
the *other* languages would catch field references at compile time that
Euphoria would force you to hunt down yourself at runtime! In other words,
the Euphoria "compiler" would have to allow code like this to pass through:

object one_card
one_card = 1
? one_card.Suit

As anyone can see, this is ridiculous. There is no way that "one_card" can
possibly contain "Card" data here. But "one_card" has the *potential* of
holding "Card"-structured data, so this *must* be allowed to pass. This will
cause an error at runtime, of course, but the point is that this shouldn't
be allowed past the "compile" step in the first place.

So, instead of allowing *that* can of worms to be opened, perhaps we ought
to say that field references are *only* valid on objects *declared* for that
specific structure. So, for the above examples, the programmer would be
forced to declare "one_card" like this:

Card one_card

Then the rest of the code follows naturally -- the Euphoria "compiler" knows
that "Suit" and "Value" are valid field-names for "one_card", because it is
explicitly defined as a "Card"-type variable. This seems to solve our
earlier problems, since the "compiler" doesn't have to do any extra work --
it always *knows* if the field references are valid or not.

However, forcing the programmer to define "one_card" in this manner creates
two problems. Firstly, it dilutes the universal nature of a generic "object"
 -- the object-defined variable can "hold" the data, but can't access it. (I
suppose it *could* access the raw data -- the sequence elements, or whatever
 -- but it couldn't use the meaningful field names.) Secondly, forcing the
programmer to specifically define the structure of the returning data can be
quite a headache, and defeats many of the advantages of using Euphoria to
begin with. It returns us to the QuickBasic way of doing things -- we *must*
define our receiving variable correctly to get meaningful data.

For example, let's say I have a function in my card-playing program like
this:

sequence Hand of Card

function draw_card_of_suit(string_9 suit)
   -- determine if we have a card of this suit
   -- if yes, return the card; if no, return 0
   for i = 1 to length(Hand) do
      if equal(Hand[i].Suit, suit) then
         -- we have a card of this suit!
         return Hand[i]
      end if
   end for
   -- we don't have a card of this suit
   return 0
end function

Now, ideally, I would like to do something like this:

   object next_card
   next_card = draw_card_of_suit("Spade")
   if Card(next_card) then
      ? next_card.Value
      ? next_card.Suit
   else
      ? "I don't have one"
   end if

I don't want to declare "next_card" as a "Card", since that will cause
problems when draw_card_of_suit() returns 0. But I *can't* define
"next_card" as an object, because the field references can *only* be
attached to "Card"-defined objects!!

So I'm forced to do this instead:

   object tmp
   Card next_card
   tmp = draw_card_of_suit("Spade")
   if Card(tmp) then
      next_card = tmp
      ? next_card.Value
      ? next_card.Suit
   else
      ? "I don't have one"
   end if

I have to declare two variables instead of one, and I'm forced to move the
object value into the "Card" structure just to access its fields. Is this
"elegant"? I don't think so.

This is just the tip of the iceberg. How about a generic sequence containing
mixed data -- all kinds of very different structures. If we want to access
their data, we've first got to type-check what's coming in; then, we're
forced to define specific variables for *each* of these structures, just so
that we can access their fields! The overhead of defining those extra
variables will certainly make performance-conscious programmers mad.

And what about backwards-compatibility? Are we *sure* that we won't pass a
structure into a routine that will treat it like a regular object? Say we
have a sequence containing many different structures, and we pass it to an
existing routine. Tragically, this existing routine has a nasty flaw which
accidentally concatenates a zero to each object in the sequence. How does
Euphoria prevent the corruption of a "structure" in this instance? How does
it know that each element of the sequence is a structure in the first place?
Is it a completely different type of object in Euphoria? If so, then how can
we implement it without breaking any existing code? How much more internal
work will Euphoria have to do to deal with the exceptional conditions raised
by structures? How much more work will the *programmers* have to do on their
existing programs if structures are introduced into the language?

I could go on, but I trust my point is clear. Structures will not "simplify"
anything in Euphoria -- they will add a whole slew of new rules and
exceptions to existing rules. Whether you *want* to use them or not will
make no difference -- they *will* have an effect on how you write your
programs. The kinds of structures described here *cannot* work within the
context of Euphoria. The reason is simple -- they do not fit! These
structure ideas all have their roots in rigid, every-data-type-defined
programming languages, and there's no way we can introduce them into
Euphoria -- not without a lot of fundamental changes to the language.

Introducing structures into Euphoria would *not* turn it into C. But it
would be very different from the Euphoria we all know and love.

Gabriel Boehme

new topic     » topic index » view message » categorize

2. Re: Problems with structures

>I agree that something *like* structures is needed and would be very useful
>in Euphoria, for very much the same reasons they're useful in other
>languages. An example from QuickBasic:


True. I'm glad the discussion on structures has matured past "We need
structures" and "Structures are from C, so I don't like them". I just hope
it stays that way. smile

>TYPE Card
>    Suit AS STRING * 9
>    Value AS INTEGER
>END TYPE
>
>DIM Deck(1 TO 52) AS Card
>Deck(1).Suit = "Club"
>Deck(1).Value = 2
>PRINT Deck(1).Suit, Deck(1).Value


>As you can see, it's very easy to understand what's going on here. You have
>a deck of 52 cards, identified here by suit and value. You don't have to
>define constants to use as subscripts (i.e. Suit = 1, Value = 2) -- you can
>give the individual portions field names to uniquely identify them. Plus,
>the compiler will *always* know if a field reference is valid or not, and
>can tell you right away if you've made a mistake. If I were to try this...
>
>DIM Hand(1 TO 7) AS STRING * 9
>Hand(1).Suit = "Spade"
>
>..the compiler would immediately flag it as an error -- the "Hand" array is
>not defined to contain "Card"-type data, so the ".Suit" reference has no
>meaning here. The same goes for all the other languages containing
>structures -- since every data element's type *must* be defined beforehand,
>the compiler can know instantly if a field reference is valid or not.


Right. Argument #1 for structures: Type checking. Argument #2 hasn't been
touched on in your message, so I'll point it out here: Speed. Structures, in
theory, should be faster than the dynamic sequence Euphoria has.

>Now, let's look at a Euphoria-style example, based on the above. [Note: in
>all my examples, I will use "?" to indicate general screen output, rather
>than the specific "?" statement.]
>
> -- we'll assume the string_9() type is already defined as a
>maximum-length-9 sequence of integer values
>
>structure Card
>   string_9 Suit
>   integer Value
>end structure
>
>sequence Deck of Card
>
> -- we'll ignore for the moment the problem of initialization...
>
>Deck[1].Suit = "Club"
>Deck[1].Value = 2
>? Deck[1]
>
>This seems just fine, doesn't it? Just throw in structure definitions and
>"of" statements and you're all set! It sure *seems* to simplify things --
>and if you don't like it, just don't use structures! That's pretty much the
>pro-structure viewpoint, and it seems quite reasonable at first glance.


Well, that's why it got so much support. Then a few of us thought about
it... There is a *LOT* of special syntax associated with structures in other
languages.

>string_9 Hand of Card
>
>What is the interpreter to do? Yes, the "string_9" type conflicts with the
>"Card" structure, but the interpreter won't know that until "Hand" is
>initialized -- at *runtime*. This can cause much confusion, since a
>definition like this won't cause a "compile" error. I suppose we could
>restrict the "of" clause to be used only with "sequence" declarations, but
>then what if we have our own user-defined sequence types that we *want* to
>use with "of"? Like this:


What about:

Card Hand -- Define Hand as Card.
sequence Card Hand -- Make it an "array"

Now, before you say the interpreter could see this:

sequence Card
Hand

Remember: What would happen here:

type Card(atom x)
    return atom(x)
end type

sequence Card

We get an error, right? That's because the interpreter *KNOWS* that Card has
been defined as a type. Now, if it *KNOWS* that Card was defined as a
structure, then it would know what to do with the next "line". The only
problem is that Euphoria's syntax is usually pretty predictable. This is
slightly less consistent.

Now, this next argument you provide, has one huge flaw in it:

>Secondly, examples such as these don't deal adequately with generic
Euphoria
>objects. Most of the structure ideas I've seen show how we could define and
>use the structures, but don't really examine how *normal* Euphoria would
>work with them. What if I try this:
>
>object one_card
>one_card = Deck[1]
>? one_card.Suit
>? one_card.Value
>
>It seems simple enough at first glance -- the object "one_card" is assigned
>the value from "Deck[1]", which is in "Card" format. So naturally the field
>references would make sense. But how does the Euphoria "compiler" know for
>sure what's in "one_card"? How does it know that "one_card.Suit" is a valid
>field reference? After all, "one_card" is a generic object. There's no
>guarantee that it will *always* contain "Card"-structured data. In theory,
I
>suppose the Euphoria "compiler" could try to get really clever  -- it knows
>that "Deck[1]" contains "Card"-structured data, so it "allows" the field
>references to be attached to the object "one_card" in this particular case.
>In practice, however, this would be a *nightmare* to implement, especially
>if the value is passed back via a function:

Well, how does Euphoria know that an object is a sequence or atom? It would
also know if it is a structure or not. Think about this:

object a
a = 1
? a[1]  -- Error!

Why on Earth would it do that? Could it be that Euphoria somehow magically
knew that a was currently an atom? So why would it be so hard to keep this
from happening?

Object a
a = 1
? a.Suit

Same basic principle: Access a part of a that doesn't exist. Both cases, a
crash.

>object one_card
>one_card = 1
>? one_card.Suit
>
>As anyone can see, this is ridiculous. There is no way that "one_card" can
>possibly contain "Card" data here. But "one_card" has the *potential* of
>holding "Card"-structured data, so this *must* be allowed to pass. This
will
>cause an error at runtime, of course, but the point is that this shouldn't
>be allowed past the "compile" step in the first place.


Euphoria wouldn't allow one_card[1] to pass (at runtime). But it has the
*potential* of holding sequence data, so it *must* be allowed to pass,
right? It would crash at runtime. I don't see any problem here. Well, this
problem already exists... So I don't see any NEW problem with the crashing
with structures. blink

>This is just the tip of the iceberg. How about a generic sequence
containing
>mixed data -- all kinds of very different structures. If we want to access
>their data, we've first got to type-check what's coming in; then, we're
>forced to define specific variables for *each* of these structures, just so
>that we can access their fields! The overhead of defining those extra
>variables will certainly make performance-conscious programmers mad.


Kinda works against that 'speed' theory of ours, eh? And initializing the
structures is also something that hasn't been worked out.

>I could go on, but I trust my point is clear. Structures will not
"simplify"
>anything in Euphoria -- they will add a whole slew of new rules and
>exceptions to existing rules. Whether you *want* to use them or not will
>make no difference -- they *will* have an effect on how you write your
>programs. The kinds of structures described here *cannot* work within the
>context of Euphoria. The reason is simple -- they do not fit! These
>structure ideas all have their roots in rigid, every-data-type-defined
>programming languages, and there's no way we can introduce them into
>Euphoria -- not without a lot of fundamental changes to the language.
>
>Introducing structures into Euphoria would *not* turn it into C. But it
>would be very different from the Euphoria we all know and love.


And this is actually the only really good argument against structures: They
just don't fit. As was pointed out, we need "something".

Something that fits these three parameters, of possible:

Is faster when not being resized. Remember, there is a lot of code that uses
a sequence to emulate a structure. The 2nd level, usually, never grows or
shrinks. Could the speed to access such a non-dynamic part of a sequence be
sped up? Is it already like that?

Has type-checking: What if the data of a sequence, which somewhere has an
atom where it should have a sequence, is sent to a generic save-to-disk
routine? Then when it is loaded, the corrupted data will crash when sent as
an argument to say pixel() as the coordinents. This could be a tough bug to
track down, especially in a large program saved to disk by Edom. (Data isn't
human-readable on disk) trace() would be the only hope, and it WOULD work,
it would just take a bit of work.

Elemenates name-space conflicts. If two pseudo structures have the same
field, LIFE, then that field has to be in the *SAME SPOT* in each structure,
because we can't have two constant declarations of LIFE. This can be quite
irritating, when you have to reorder a logically based constant order
because you need another pseudo structure to have access to LIFE. I have run
into this porting C code to Euphoria. It can be worked around, but it is
*VERY* annoying.

new topic     » goto parent     » topic index » view message » categorize

3. Re: Problems with structures

Robert Pilkington <pilking at BELLATLANTIC.NET> writes:

>>As you can see, it's very easy to understand what's going on here. You
have
>>a deck of 52 cards, identified here by suit and value. You don't have to
>>define constants to use as subscripts (i.e. Suit = 1, Value = 2) -- you
can
>>give the individual portions field names to uniquely identify them. Plus,
>>the compiler will *always* know if a field reference is valid or not, and
>>can tell you right away if you've made a mistake. If I were to try this...
>>
>>DIM Hand(1 TO 7) AS STRING * 9
>>Hand(1).Suit = "Spade"
>>
>>..the compiler would immediately flag it as an error -- the "Hand" array
is
>>not defined to contain "Card"-type data, so the ".Suit" reference has no
>>meaning here. The same goes for all the other languages containing
>>structures -- since every data element's type *must* be defined
beforehand,
>>the compiler can know instantly if a field reference is valid or not.
>
>
>Right. Argument #1 for structures: Type checking. Argument #2 hasn't been
>touched on in your message, so I'll point it out here: Speed. Structures,
in
>theory, should be faster than the dynamic sequence Euphoria has.

I would agree with argument #1, on some level -- named references should be
available *somehow*. But it doesn't work within the context of Euphoria.
Neither does argument #2, not that I can see. Read on for more details...

>What about:
>
>Card Hand -- Define Hand as Card.
>sequence Card Hand -- Make it an "array"

Does Euphoria have arrays? No. Euphoria has *sequences*. Once again, we are
creating contradictory syntax for sequence definitions, and diluting the
*essential* features of generic sequences...

>Now, before you say the interpreter could see this:
>
>sequence Card
>Hand
>
>Remember: What would happen here:
>
>type Card(atom x)
>    return atom(x)
>end type
>
>sequence Card
>
>We get an error, right? That's because the interpreter *KNOWS* that Card
has
>been defined as a type. Now, if it *KNOWS* that Card was defined as a
>structure, then it would know what to do with the next "line". The only
>problem is that Euphoria's syntax is usually pretty predictable. This is
>slightly less consistent.

This is true -- "sequence structure variable" just looks confusing. This
method of variable declaration could cause problems within routines, as
well. Please try this yourself -- create a Euphoria executable containing
just this code:

type five(integer x)
   return x = 5
end type

procedure test()
integer five
   five = 4
   ? five
end procedure

test()

Now run it. Hey, it works! Type-declarations are allowed to be used as
variable names within routines. Would structures be any different?

Sequences are *by definition*, a collection of *any* Euphoria objects. The
only current restriction on this is to declare a sequence as a different
type:

my_sequence Card

This way, it's obvious how to type-check Card -- just look at the
type-declaration of my_sequence() to see what's legal. With your
three-identifier declaration, it's unclear just how the type-checking takes
place. Argument #1 for structures should not *create* any type-check
confusion -- it should *solve* it.

>Now, this next argument you provide, has one huge flaw in it:
>
>>Secondly, examples such as these don't deal adequately with generic
Euphoria
>>objects. Most of the structure ideas I've seen show how we could define
and
>>use the structures, but don't really examine how *normal* Euphoria would
>>work with them. What if I try this:
>>
>>object one_card
>>one_card = Deck[1]
>>? one_card.Suit
>>? one_card.Value
>>
>>It seems simple enough at first glance -- the object "one_card" is
assigned
>>the value from "Deck[1]", which is in "Card" format. So naturally the
field
>>references would make sense. But how does the Euphoria "compiler" know for
>>sure what's in "one_card"? How does it know that "one_card.Suit" is a
valid
>>field reference? After all, "one_card" is a generic object. There's no
>>guarantee that it will *always* contain "Card"-structured data. In theory,
I
>>suppose the Euphoria "compiler" could try to get really clever  -- it
knows
>>that "Deck[1]" contains "Card"-structured data, so it "allows" the field
>>references to be attached to the object "one_card" in this particular
case.
>>In practice, however, this would be a *nightmare* to implement, especially
>>if the value is passed back via a function:
>
>Well, how does Euphoria know that an object is a sequence or atom? It would
>also know if it is a structure or not. Think about this:
>
>object a
>a = 1
>? a[1]  -- Error!
>
>Why on Earth would it do that? Could it be that Euphoria somehow magically
>knew that a was currently an atom? So why would it be so hard to keep this
>from happening?
>
>Object a
>a = 1
>? a.Suit
>
>Same basic principle: Access a part of a that doesn't exist. Both cases, a
>crash.

Yes, but a crash at *runtime*. Structures in every other language can be
verified at "compile" time. Euphoria won't flag "? a[1]" as an error until
the statement is actually executed. Please, try this on your own -- create a
Euphoria executable containing *just* this code:

procedure try_this()
   object a
   a = 1
   ? a[1]
end procedure

Notice that we're *not* calling try_this() from anywhere, so we're not
executing anything. The only way "? a[1]" can be flagged as an error is if
the "compiler" catches it. Now run the executable. Well, what do you know,
no errors!

Again, every other language can verify its structure field references at
compile-time -- please refer back to the QuickBasic example given at the
beginning. Euphoria's "compiler" would be unable to do this. True, it lets
subscript references like "a[1]" go by, but subscripts at least potentially
apply to *any* sequence within the program. Structure field names would
*only* apply to their specifically-defined structures -- yet they, too must
be allowed *anywhere* in the program. Programmers from other languages would
wonder why Euphoria is unable to do "compile"-time field reference checks.

>>object one_card
>>one_card = 1
>>? one_card.Suit
>>
>>As anyone can see, this is ridiculous. There is no way that "one_card" can
>>possibly contain "Card" data here. But "one_card" has the *potential* of
>>holding "Card"-structured data, so this *must* be allowed to pass. This
will
>>cause an error at runtime, of course, but the point is that this shouldn't
>>be allowed past the "compile" step in the first place.
>
>
>Euphoria wouldn't allow one_card[1] to pass (at runtime). But it has the
>*potential* of holding sequence data, so it *must* be allowed to pass,
>right? It would crash at runtime. I don't see any problem here. Well, this
>problem already exists... So I don't see any NEW problem with the crashing
>with structures. blink

With "one_card[1]", Euphoria doesn't have to do any major type-check work to
determine if "one_card" is a sequence or atom. For "one_card.Suit", how will
Euphoria know if "one_card" contains "Card"-type data? Why, it will have to
do a type-check, of course -- EVERY TIME IT'S REFERENCED WITH A FIELD NAME.

object one_card
one_card = Deck[1]
? one_card.Suit  -- type-check required here
? one_card.Value  -- type-check required here, too

This would be a MAJOR performance-killer. Kinda goes against argument #2 for
structures, doesn't it?

True, the "without type_check" directive could turn this off. But this would
(again!) create major changes in the way Euphoria does business. Currently,
the only time it needs to do user-defined type-checks is when a value is
assigned to the variable -- now it needs to do them just to *reference* the
varaible!


>And this is actually the only really good argument against structures: They
>just don't fit. As was pointed out, we need "something".
>
>Something that fits these three parameters, of possible:
>
>Is faster when not being resized. Remember, there is a lot of code that
uses
>a sequence to emulate a structure. The 2nd level, usually, never grows or
>shrinks. Could the speed to access such a non-dynamic part of a sequence be
>sped up? Is it already like that?

This might be a possibility. However, Euphoria's current design allows for
changes to *any* of the sequences. Exceptions would require extra logic,
which would kill speed.

>Has type-checking: What if the data of a sequence, which somewhere has an
>atom where it should have a sequence, is sent to a generic save-to-disk
>routine? Then when it is loaded, the corrupted data will crash when sent as
>an argument to say pixel() as the coordinents. This could be a tough bug to
>track down, especially in a large program saved to disk by Edom. (Data
isn't
>human-readable on disk) trace() would be the only hope, and it WOULD work,
>it would just take a bit of work.

Type check the data before you access it. I don't understand why
pro-structure people are so allergic to big type-checks. They're only
performance killers when type-checking is *on*. That should be perfectly
fine when you're testing your program. When you're confident your program is
stable, you can specify "without type_check" at the beginning of your
source. It's true that this *could* be a problem if you haven't plugged all
the code leaks in your program. That's why type-checks are so cool to begin
with. Structures are an attempt to "force" Euphoria to rigidly "lock" the
types of data it can use and pass around. But structures would *still*
require type-checks -- they'd just be hidden under the surface of the
"structure" syntax. Plus, they'd introduce all sorts of other exceptional
conditions that sequences don't have to deal with, so I don't see what we're
gaining with structures.

For problems as described above -- an incoming file that has somehow become
corrupted -- just type-check your incoming data *once* before passing it on
to the rest of your program. You know, call the type like a function to
verify that the data is legal. This way, if there's a problem, you get a
very easy-to-understand type-check error -- it's stopped before it gets too
far into your program, and doesn't become "tough to track down". You still
seem to be thinking in terms of other programming languages -- *they* don't
have anything like type-checks or structure verification, so it doesn't
occur to you that Euphoria's type-checking can catch this *before* it
becomes a major problem. (I hope I'm not being too presumptuous here...)

Euphoria type-checks are the best I've found in *any* language. You can
restrict any value to any structure or range you desire. Instead of being
tied to machine-types like other languages, Euphoria allows you to logically
define your types in any way you need to. Yes, this kind of type-checking is
slower. But the flexibility and runtime safety that's gained, IMHO, is worth
the exchange.

>Elemenates name-space conflicts. If two pseudo structures have the same
>field, LIFE, then that field has to be in the *SAME SPOT* in each
structure,
>because we can't have two constant declarations of LIFE. This can be quite
>irritating, when you have to reorder a logically based constant order
>because you need another pseudo structure to have access to LIFE. I have
run
>into this porting C code to Euphoria. It can be worked around, but it is
>*VERY* annoying.

I agree with this point. But I don't see this as a structure issue -- more
of a NAMESPACE issue instead. Perhaps solutions to namespace problems will
eliminate the need for structures?

Gabriel Boehme

new topic     » goto parent     » topic index » view message » categorize

4. Re: Problems with structures

At 10:57 2/4/99 -0600, Boehme, Gabriel wrote:

...major snipping...

>I agree with this point. But I don't see this as a structure issue -- more
>of a NAMESPACE issue instead. Perhaps solutions to namespace problems will
>eliminate the need for structures?
>
>Gabriel Boehme

Yes, the namespace problem is a separate issue from structures and Rob has
already said that the namespace issue is a major focus for the next release.
IMHO, future discussion of structures would be better served without
raising the
namespace issue (or the ghost of C/C++ smile

You raise some very good points, Gabriel, about the impact of the addition of
structures on the overall language.   We need to remember TANSTAAFL (Their
Ain't No Such Thing As A Free Lunch).   Every feature comes with a cost, and
you have identified some potentially expensive costs for the addition of
structures.
--
Don Groves

--
Don Groves
groves at acm.org

If I could think of a clever tag line, this would be it.

new topic     » goto parent     » topic index » view message » categorize

5. Re: Problems with structures

Boehme, Gabriel wrote:


> I agree that something *like* structures is needed and would be very useful
> in Euphoria, for very much the same reasons they're useful in other
> languages.

The problem is not with structures. It is with wanting to implement
structures in Euphoria. Structures, period.  A structure is
a sequence with severe limitations imposed on it. A sequence in
a straight-jacket. So is this:

type string(object x)
  if atom(x) then return false
  else
     for i=1 length(x) do
     if not char(x) then return false -- I assume that type char() has
been defined
  end if
  return true
end type

Another, real problem, is some of the proposed syntax:

> sequence Deck of Card

This "of" is  borrowed from Pascal. But Pascal declarations have
a very different syntax:

[Pascal]    var x,y,z: integer;
[Euphoria]  integer x,y,z

So, as it is logical to write in Pascal
     Deck: array[1..52] of Card;
           ^^^^^^^^^^^^ of ^^^^

it is  illogical to write in Euphoria

    sequence Deck of Card
    ^^^^^^^^      of ^^^^


> ... Just throw in structure definitions and
> "of" statements and you're all set!

Even the more Euphoria-like syntax
    sequence of Card Deck

is a dreadful horror.

By definition a sequence is a list of objects, and
an object is *anything*. "Deck" is, at best,
definable as a "sequence" of sorts, upon which
such severe restrictions have been imposed as
to make it something else altogether.

> It sure *seems* to simplify things --
> and if you don't like it

It confuses things.

Let me remember my first encounter with structures.
It must have been with Turbo Pascal 1.0. Back then
I saw very little point in structures (called records
in Pascal). The "Deck" example seemed an awfully
convoluted way of implementing what I used to write:

[style 1]
var Value: array[1..52] of integer;
    Suit:  array[1..52] of integer;

or something like that, functionally equivalent to
another way I had to generate decks:

[style 2]
var Deck: array[1..52] of array[1..2] of integer;

Then, gradually, I got used to records, and found
that, sometimes, rightly used, they were more convenient
than my old ways:

type Card= record Value,Suit: integer
           end;
     Deck= array[1..52] of Card;

Shuffling and dealing were as easy as with the "style 2"
code, AND I did not have to remember which of those
two cells held the value of a card, which its suit.

(I also got into awful messes using records when
inappropriate. And objects too. And inheritance)

[Thinking-aloud mode]
Go back to "style 1". There is a bijection between
Value and Suit. "Unfold" a record (a structure if
you prefer), to turn it into "style 1" code, and
you end up with a set of arrays such that there is
a bijection between any two of them. Always. Oh... I could
now have a deck the values of which are *anything*:

{"ace low","deuce","trey",4,5,{6,0}... "ace high", ....}

Ditto its suits:

{0,{"clubs","fiori",1},....

It does not matter if such a deck is functionally useless (it
only means that I can't think of a use right now),
what matters is: Value and Suit are now Euphoria sequences,
not arrays. The only restriction imposed on them is that
they must be the same length, since there must be a
bijection between them.

[Thinking-aloud cap off]


> However, these examples (and most others I've seen) are deeply flawed,
> because they are all based on examples from other languages that *only* have
> rigid definitions for variables.

They are flawed because they try to inject the syntax and functionality
of straight-jacket languages into Euphoria. You must, starting from
the principles behind Euphoria, ... mmm... find an application of those
principles that covers the functionality of stuff like structures.
While NOT *aiming* at covering structures.


> First of all, look at the apparently harmless syntax of "sequence Deck of
> Card". Heck, it almost reads like English, doesn't it?

Indeed, the syntax is abominable, the semantics absurd, and I am not
even going into what the interpreter is supposed to make of it.
Yes, I know: since it makes no sense, treat it as a comment smile


> I could go on, but I trust my point is clear. Structures will not "simplify"
> anything in Euphoria -- they will add a whole slew of new rules and
> exceptions to existing rules.

It depends how they are implemented. It they are a mere side-effect of
an extension of Euphoria, an extension which does not modify the
language, but *amplifies* it, then, there is no harm done. Right now
you can write structures in two ways ("style 1" and "style 2" above).
It only becomes terribly awkward when you feel the need for symbolic
constants to index those "structured" sequences.


At least, all this my ranting had the advantage of reminding me
of the old way I used to represent structures, before I learnt C,
before I learnt Pascal. "Style 1" might turn out to be easier for
my purpose. I'll see.

Jacques Guy

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu