www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Array indexing & typedef

reply Charles Hixson <charleshixsn earthlink.net> writes:
Does:
typedef int MyType;
char[MyType]	val;

result in val being an associative array, rather than an arrays 
whose indicies are typechecked to be instances of MyType?

If so, is there a valid way of specifying that one wants an array 
of items which is indexed by a specialized type of integer short 
of defining a new class?

If not, what's the approved way to define an associative array 
with an index of ints?

I'm certain that this must have come up before, but I haven't 
been able to find it.
Jun 19 2005
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Charles Hixson" <charleshixsn earthlink.net> wrote in message 
news:d950du$2u4c$1 digitaldaemon.com...
 Does:
 typedef int MyType;
 char[MyType] val;

 result in val being an associative array, rather than an arrays whose 
 indicies are typechecked to be instances of MyType?

Yes. Any time you put _any_ kind of type inside the brackets, it's an AA. This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."
Jun 19 2005
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
Jarrett Billingsley wrote:
 "Charles Hixson" <charleshixsn earthlink.net> wrote in message 
 news:d950du$2u4c$1 digitaldaemon.com...
 
Does:
typedef int MyType;
char[MyType] val;

result in val being an associative array, rather than an arrays whose 
indicies are typechecked to be instances of MyType?

Yes. Any time you put _any_ kind of type inside the brackets, it's an AA. This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."

Unfortunately, what I wanted wasn't a sparse array, but an array that required it's indexes to be a particular type... O, well. At other times I want sparse arrays...so that's all to the good. Any suggestions as to how to require indexes to be of a particular type? (All I can think of is building a class, and implementing optAssign, etc.)
Jun 20 2005
next sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Mon, 20 Jun 2005 13:34:14 -0700, Charles Hixson  
<charleshixsn earthlink.net> wrote:
 Jarrett Billingsley wrote:
 "Charles Hixson" <charleshixsn earthlink.net> wrote in message  
 news:d950du$2u4c$1 digitaldaemon.com...

 Does:
 typedef int MyType;
 char[MyType] val;

 result in val being an associative array, rather than an arrays whose  
 indicies are typechecked to be instances of MyType?

an AA. This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."

Unfortunately, what I wanted wasn't a sparse array, but an array that required it's indexes to be a particular type... O, well. At other times I want sparse arrays...so that's all to the good. Any suggestions as to how to require indexes to be of a particular type? (All I can think of is building a class, and implementing optAssign, etc.)

I dont understand what you want. It seems like you're saying you want a normal array i.e. sequentialy indexed items and you want to limit which type can be used to index it to? why? I'd guess you have something like: class Bar{} enum Foo { A,B,C,D,E,F,G } Bar[G] data; and you're trying to get the compiler to limit the indices to the 'data' array to the enumerated type, or similar. Am I on the right track? Regan
Jun 20 2005
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
Regan Heath wrote:
 On Mon, 20 Jun 2005 13:34:14 -0700, Charles Hixson  
 <charleshixsn earthlink.net> wrote:
 Jarrett Billingsley wrote:
 "Charles Hixson" <charleshixsn earthlink.net> wrote in message  
 news:d950du$2u4c$1 digitaldaemon.com...

 Does:
 typedef int MyType;
 char[MyType] val;

 result in val being an associative array, rather than an arrays 
 whose  indicies are typechecked to be instances of MyType?

it's an AA. This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."

Unfortunately, what I wanted wasn't a sparse array, but an array that required it's indexes to be a particular type... O, well. At other times I want sparse arrays...so that's all to the good. Any suggestions as to how to require indexes to be of a particular type? (All I can think of is building a class, and implementing optAssign, etc.)

I dont understand what you want. It seems like you're saying you want a normal array i.e. sequentialy indexed items and you want to limit which type can be used to index it to? why? I'd guess you have something like: class Bar{} enum Foo { A,B,C,D,E,F,G } Bar[G] data; and you're trying to get the compiler to limit the indices to the 'data' array to the enumerated type, or similar. Am I on the right track? Regan

languages at once). In Ada if one defines a type and then defines an array type, say: Type GoalRange is Integer range 0...MaxGoal; Type Goals is array (GoalRange) of Goal; then it's a compilation error if you index the array with a variable of any type other than GoalRange. This isn't necessary in order to translate the program...but it does add a layer of error checking at compile time that I think useful...*!*IF*!* I can add it without too much work. (OTOH, Ada doesn't have built in hash tables...and I've been scratching my head around how to replace tree searches that aren't well documented [now where is this "out" variable used...and WHY??].) OTOH, replacing GoalRange with an enumeration is a bit ... strange. There will probably be less than a few hundred goals...but they will come and go. (It's a backwards chaining "Expert System Shell"...of the old and "simple" variety.) The two languages are VERY different, and the right way to do things frequently changes GROSSLY when I translate it. (At one point I nearly gave up and said.."I'll just do a literal translation!", but really, that's the wrong approach. I wouldn't be doing this at all if I weren't trying to learn from the process.) OTOH, a sparse array / hash table is definitely NOT what I want where I'm just looking to enforce type safety. (But I sure do want it at other times!)
Jun 21 2005
next sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Tue, 21 Jun 2005 20:28:31 -0700, Charles Hixson  
<charleshixsn earthlink.net> wrote:
 Regan Heath wrote:
 On Mon, 20 Jun 2005 13:34:14 -0700, Charles Hixson   
 <charleshixsn earthlink.net> wrote:
 Jarrett Billingsley wrote:
 "Charles Hixson" <charleshixsn earthlink.net> wrote in message   
 news:d950du$2u4c$1 digitaldaemon.com...

 Does:
 typedef int MyType;
 char[MyType] val;

 result in val being an associative array, rather than an arrays  
 whose  indicies are typechecked to be instances of MyType?

it's an AA. This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."

Unfortunately, what I wanted wasn't a sparse array, but an array that required it's indexes to be a particular type... O, well. At other times I want sparse arrays...so that's all to the good. Any suggestions as to how to require indexes to be of a particular type? (All I can think of is building a class, and implementing optAssign, etc.)

a normal array i.e. sequentialy indexed items and you want to limit which type can be used to index it to? why? I'd guess you have something like: class Bar{} enum Foo { A,B,C,D,E,F,G } Bar[G] data; and you're trying to get the compiler to limit the indices to the 'data' array to the enumerated type, or similar. Am I on the right track? Regan

at once). In Ada if one defines a type and then defines an array type, say: Type GoalRange is Integer range 0...MaxGoal; Type Goals is array (GoalRange) of Goal; then it's a compilation error if you index the array with a variable of any type other than GoalRange. This isn't necessary in order to translate the program...but it does add a layer of error checking at compile time that I think useful...

Yeah, that is basically what I figured you wanted. I agree it would be useful.
 *!*IF*!* I can add it without too much work.  (OTOH, Ada doesn't have  
 built in hash tables...and I've been scratching my head around how to  
 replace tree searches that aren't well documented [now where is this  
 "out" variable used...and WHY??].)

I'm sorry I can't help with Ada. I've never used it.
 OTOH, replacing GoalRange with an enumeration is a bit ... strange.

Yeah, but it's the closest built in basic type to a 'range' that D has I reckon. I D got ranges I'd imagine them built onto the enum syntax eg. enum myInt : int { 0,...,100 } enum myInt : int { 0 ... 100 } or something similar. There have been a number of requests for a range type in D, I can't remember Walter's position (or even if he gave one). I suspect at this stage 'ranges', while useful, are not high on the list of things to do.
 OTOH, a sparse array / hash table is definitely NOT what I want where  
 I'm just looking to enforce type safety.  (But I sure do want it at  
 other times!)

Sure, they're kind of overkill really for this problem. Tho, they'd do the job, right? Regan
Jun 21 2005
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
Regan Heath wrote:
 On Tue, 21 Jun 2005 20:28:31 -0700, Charles Hixson  
 <charleshixsn earthlink.net> wrote:
 Regan Heath wrote:
 On Mon, 20 Jun 2005 13:34:14 -0700, Charles Hixson   
 <charleshixsn earthlink.net> wrote:
 Jarrett Billingsley wrote:
 "Charles Hixson" <charleshixsn earthlink.net> wrote in message   
 news:d950du$2u4c$1 digitaldaemon.com...

 Does:
 typedef int MyType;
 char[MyType] val;

 result in val being an associative array, rather than an arrays  
 whose  indicies are typechecked to be instances of MyType?

it's an AA. This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."

Unfortunately, what I wanted wasn't a sparse array, but an array that required it's indexes to be a particular type... O, well. At other times I want sparse arrays...so that's all to the good. Any suggestions as to how to require indexes to be of a particular type? (All I can think of is building a class, and implementing optAssign, etc.)

want a normal array i.e. sequentialy indexed items and you want to limit which type can be used to index it to? why? I'd guess you have something like: class Bar{} enum Foo { A,B,C,D,E,F,G } Bar[G] data; and you're trying to get the compiler to limit the indices to the 'data' array to the enumerated type, or similar. Am I on the right track? Regan

languages at once). In Ada if one defines a type and then defines an array type, say: Type GoalRange is Integer range 0...MaxGoal; Type Goals is array (GoalRange) of Goal; then it's a compilation error if you index the array with a variable of any type other than GoalRange. This isn't necessary in order to translate the program...but it does add a layer of error checking at compile time that I think useful...

Yeah, that is basically what I figured you wanted. I agree it would be useful.
 *!*IF*!* I can add it without too much work.  (OTOH, Ada doesn't have  
 built in hash tables...and I've been scratching my head around how to  
 replace tree searches that aren't well documented [now where is this  
 "out" variable used...and WHY??].)

I'm sorry I can't help with Ada. I've never used it.
 OTOH, replacing GoalRange with an enumeration is a bit ... strange.

Yeah, but it's the closest built in basic type to a 'range' that D has I reckon. I D got ranges I'd imagine them built onto the enum syntax eg. enum myInt : int { 0,...,100 } enum myInt : int { 0 ... 100 } or something similar. There have been a number of requests for a range type in D, I can't remember Walter's position (or even if he gave one). I suspect at this stage 'ranges', while useful, are not high on the list of things to do.
 OTOH, a sparse array / hash table is definitely NOT what I want where  
 I'm just looking to enforce type safety.  (But I sure do want it at  
 other times!)

Sure, they're kind of overkill really for this problem. Tho, they'd do the job, right? Regan

as long as you could distinguish null from out-of-range. But hash tables aren't intended for stepping through, and arrays are. You could force them to do the job...but that would be worse than writing a new container class (which looks to be relatively minor), and would probably be much more inefficient. (Done right, all the overhead [over an array of integers] should be at compile time.) Still, this really IS minor. I can skip the layer of error checking, and use alias instead of typedef...or I can write the container classes (which might be good practice anyway). But I'd need to write it several times, because I'm NOT ready to start dealing with templates yet. (For some reason, that's the feature of D that makes less sense to me than any of the others. I far prefer the way that Eiffel uses generics [or did 5 years ago] to handle the same problem.)
Jun 22 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 22 Jun 2005 08:21:06 -0700, Charles Hixson  
<charleshixsn earthlink.net> wrote:
 Regan Heath wrote:
 On Tue, 21 Jun 2005 20:28:31 -0700, Charles Hixson   
 <charleshixsn earthlink.net> wrote:
 Regan Heath wrote:
 On Mon, 20 Jun 2005 13:34:14 -0700, Charles Hixson    
 <charleshixsn earthlink.net> wrote:
 Jarrett Billingsley wrote:
 "Charles Hixson" <charleshixsn earthlink.net> wrote in message    
 news:d950du$2u4c$1 digitaldaemon.com...

 Does:
 typedef int MyType;
 char[MyType] val;

 result in val being an associative array, rather than an arrays   
 whose  indicies are typechecked to be instances of MyType?

it's an AA. This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."

Unfortunately, what I wanted wasn't a sparse array, but an array that required it's indexes to be a particular type... O, well. At other times I want sparse arrays...so that's all to the good. Any suggestions as to how to require indexes to be of a particular type? (All I can think of is building a class, and implementing optAssign, etc.)

want a normal array i.e. sequentialy indexed items and you want to limit which type can be used to index it to? why? I'd guess you have something like: class Bar{} enum Foo { A,B,C,D,E,F,G } Bar[G] data; and you're trying to get the compiler to limit the indices to the 'data' array to the enumerated type, or similar. Am I on the right track? Regan

languages at once). In Ada if one defines a type and then defines an array type, say: Type GoalRange is Integer range 0...MaxGoal; Type Goals is array (GoalRange) of Goal; then it's a compilation error if you index the array with a variable of any type other than GoalRange. This isn't necessary in order to translate the program...but it does add a layer of error checking at compile time that I think useful...

be useful.
 *!*IF*!* I can add it without too much work.  (OTOH, Ada doesn't have   
 built in hash tables...and I've been scratching my head around how to   
 replace tree searches that aren't well documented [now where is this   
 "out" variable used...and WHY??].)

 OTOH, replacing GoalRange with an enumeration is a bit ... strange.

I reckon. I D got ranges I'd imagine them built onto the enum syntax eg. enum myInt : int { 0,...,100 } enum myInt : int { 0 ... 100 } or something similar. There have been a number of requests for a range type in D, I can't remember Walter's position (or even if he gave one). I suspect at this stage 'ranges', while useful, are not high on the list of things to do.
 OTOH, a sparse array / hash table is definitely NOT what I want where   
 I'm just looking to enforce type safety.  (But I sure do want it at   
 other times!)

the job, right? Regan

as you could distinguish null from out-of-range. But hash tables aren't intended for stepping through, and arrays are. You could force them to do the job...but that would be worse than writing a new container class (which looks to be relatively minor), and would probably be much more inefficient. (Done right, all the overhead [over an array of integers] should be at compile time.) Still, this really IS minor. I can skip the layer of error checking, and use alias instead of typedef...or I can write the container classes (which might be good practice anyway). But I'd need to write it several times, because I'm NOT ready to start dealing with templates yet. (For some reason, that's the feature of D that makes less sense to me than any of the others. I far prefer the way that Eiffel uses generics [or did 5 years ago] to handle the same problem.)

Just for fun if you post the container here I'll try and turn it into a template class.
Jun 22 2005
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
Regan Heath wrote:
 On Wed, 22 Jun 2005 08:21:06 -0700, Charles Hixson  
 <charleshixsn earthlink.net> wrote:
 Regan Heath wrote:
 On Tue, 21 Jun 2005 20:28:31 -0700, Charles Hixson   
 <charleshixsn earthlink.net> wrote:
 Regan Heath wrote:
 On Mon, 20 Jun 2005 13:34:14 -0700, Charles Hixson    
 <charleshixsn earthlink.net> wrote:
 Jarrett Billingsley wrote:
 "Charles Hixson" <charleshixsn earthlink.net> wrote in message    
 news:d950du$2u4c$1 digitaldaemon.com...

 Does:
 typedef int MyType;
 char[MyType] val;

 result in val being an associative array, rather than an 
 arrays   whose  indicies are typechecked to be instances of MyType?

brackets, it's an AA. This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."

Unfortunately, what I wanted wasn't a sparse array, but an array that required it's indexes to be a particular type... O, well. At other times I want sparse arrays...so that's all to the good. Any suggestions as to how to require indexes to be of a particular type? (All I can think of is building a class, and implementing optAssign, etc.)

want a normal array i.e. sequentialy indexed items and you want to limit which type can be used to index it to? why? I'd guess you have something like: class Bar{} enum Foo { A,B,C,D,E,F,G } Bar[G] data; and you're trying to get the compiler to limit the indices to the 'data' array to the enumerated type, or similar. Am I on the right track? Regan

languages at once). In Ada if one defines a type and then defines an array type, say: Type GoalRange is Integer range 0...MaxGoal; Type Goals is array (GoalRange) of Goal; then it's a compilation error if you index the array with a variable of any type other than GoalRange. This isn't necessary in order to translate the program...but it does add a layer of error checking at compile time that I think useful...

be useful.
 *!*IF*!* I can add it without too much work.  (OTOH, Ada doesn't 
 have   built in hash tables...and I've been scratching my head 
 around how to   replace tree searches that aren't well documented 
 [now where is this   "out" variable used...and WHY??].)

 OTOH, replacing GoalRange with an enumeration is a bit ... strange.

has I reckon. I D got ranges I'd imagine them built onto the enum syntax eg. enum myInt : int { 0,...,100 } enum myInt : int { 0 ... 100 } or something similar. There have been a number of requests for a range type in D, I can't remember Walter's position (or even if he gave one). I suspect at this stage 'ranges', while useful, are not high on the list of things to do.
 OTOH, a sparse array / hash table is definitely NOT what I want 
 where   I'm just looking to enforce type safety.  (But I sure do 
 want it at   other times!)

do the job, right? Regan

long as you could distinguish null from out-of-range. But hash tables aren't intended for stepping through, and arrays are. You could force them to do the job...but that would be worse than writing a new container class (which looks to be relatively minor), and would probably be much more inefficient. (Done right, all the overhead [over an array of integers] should be at compile time.) Still, this really IS minor. I can skip the layer of error checking, and use alias instead of typedef...or I can write the container classes (which might be good practice anyway). But I'd need to write it several times, because I'm NOT ready to start dealing with templates yet. (For some reason, that's the feature of D that makes less sense to me than any of the others. I far prefer the way that Eiffel uses generics [or did 5 years ago] to handle the same problem.)

Just for fun if you post the container here I'll try and turn it into a template class.

using optCatAssign, and I have to call optIndex as a function rather than using [] access. There seem to be type problems that I don't understand. (Sample use at the end.) I haven't tested the code yet beyond getting it to compile, but it's hardly a complete application. typedef uint SymbolId; typedef uint IndexId; typedef char[] Token; class Symbols { protected class Symbol { Token token; SymbolId symbolId; bit arithme; bit defined; float value; IndexId indexId; this (Token t) { token = t; symbolId = cast(SymbolId)symbols.length; } } SymbolId nxtSymbolId = 0; Symbol[] symbols; /* note that the symbNdx hash table can be rebuilt as needed * from the symbols array. Thus it need not be saved. */ SymbolId[Token] symbNdx; invariant { // does nxtSymbolId have any other use? If so, why? assert (nxtSymbolId == symbols.length); // Make sure the index is kept current assert (symbols.length == symbNdx.length); } bit search(Symbol symbol) { return search(symbol.token); } public //this () { super(); } this () { } bit search(SymbolId symbolId) { if (symbolId >= symbols.length) return false; if (symbols[symbolId] !is null) assert(symbols[symbolId].symbolId == symbolId); return (symbols[symbolId] !is null); } bit search(Token token) { return search(symbNdx[token]); } this(char[] name) { } Token optIndex(SymbolId symbolId) { if (symbolId >= symbols.length) return null; return symbols[symbolId].token; } SymbolId optIndex(Token token) { assert (token !is null); return symbNdx[token]; } void optCatAssign(Token token) in { assert (token !is null); } body { Symbol symb; if (search (token) ) { // do we really want to allow symbols to be redefined? throw new SymbolException ("attempt to redefine existing symbol"); } else { nxtSymbolId += 1; symbNdx[token] = cast(SymbolId)symbols.length; symbols ~= new Symbol(token); } } void append(Token token) in { assert (token !is null); } body { Symbol symb; if (search (token) ) { // do we really want to allow symbols to be redefined? throw new SymbolException ("attempt to redefine existing symbol"); } else { nxtSymbolId += 1; symbNdx[token] = cast(SymbolId)symbols.length; symbols ~= new Symbol(token); } } } ++++++++++++++++++++++++ in a new file ++++++++++++++++++++++++ import symbol; SymbolId makeSym(inout Symbols symbols, in Token phrase) { symbols.append(phrase); //return symbols[cast(Token)phrase]; return symbols.optIndex(phrase); }
Jun 23 2005
next sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Thu, 23 Jun 2005 17:00:25 -0700, Charles Hixson  
<charleshixsn earthlink.net> wrote:
 OK, here it is.  Note that I had to define append rather than using  
 optCatAssign, and I have to call optIndex as a function rather than  
 using [] access.  There seem to be type problems that I don't  
 understand.  (Sample use at the end.)

It's opIndex, not optIndex, that's why it wasn't working.
 I haven't tested the code yet beyond getting it to compile, but it's  
 hardly a complete application.

Missing was TokenException (I defined one). I'll see what I come up with, no promises :) Regan p.s. the code below is really weirdly formatted, extra double spaced everywhere.. was that intentional or a result of the NG?
 typedef	uint	SymbolId;
 typedef	uint	IndexId;
 typedef	char[]	Token;
 class Symbols
 {
 protected
     class   Symbol
     {  Token      token;
        SymbolId   symbolId;
        bit      arithme;
        bit      defined;
        float      value;
        IndexId   indexId;

        this   (Token   t)
        {   token   =   t;
           symbolId   =   cast(SymbolId)symbols.length;
        }
     }
     SymbolId   nxtSymbolId   =   0;
     Symbol[]      symbols;
     /*   note   that   the   symbNdx   hash   table   can   be rebuilt    
 as   needed
        *   from   the   symbols   array.      Thus   it   need not    
 be   saved.
        */
     SymbolId[Token]   symbNdx;
     invariant
     {   //   does   nxtSymbolId   have   any   other   use? If   so,    
 why?
        assert   (nxtSymbolId   ==   symbols.length);
        //   Make   sure   the   index   is   kept   current
        assert   (symbols.length   ==   symbNdx.length);
     }
     bit   search(Symbol   symbol)
     {   return   search(symbol.token);   }
 public
     //this   ()   {   super();   }
     this   ()      {   }
     bit   search(SymbolId   symbolId)
     {   if   (symbolId   >=   symbols.length)   return   false;
        if   (symbols[symbolId]   !is   null)
           assert(symbols[symbolId].symbolId   ==   symbolId);
        return   (symbols[symbolId]   !is   null);
     }
     bit   search(Token   token)
     {   return   search(symbNdx[token]);   }
     this(char[]   name)
     {
     }
     Token   optIndex(SymbolId   symbolId)
     {   if   (symbolId   >=   symbols.length)   return   null;
        return   symbols[symbolId].token;
     }
     SymbolId   optIndex(Token   token)
     {   assert   (token   !is   null);
        return   symbNdx[token];
     }

     void   optCatAssign(Token   token)
     in   {   assert   (token   !is   null);   }
     body
     {   Symbol   symb;
        if   (search   (token)   )
        {   //   do   we   really   want   to   allow   symbols to   be    
 redefined?
           throw   new   SymbolException
                       ("attempt   to   redefine   existing symbol");
        }
        else
        {   nxtSymbolId   +=   1;
           symbNdx[token]   =   cast(SymbolId)symbols.length;
           symbols   ~=   new   Symbol(token);
        }
     }
     void   append(Token   token)
     in   {   assert   (token   !is   null);   }
     body
     {   Symbol   symb;
        if   (search   (token)   )
        {   //   do   we   really   want   to   allow   symbols to   be    
 redefined?
           throw   new   SymbolException
                       ("attempt   to   redefine   existing symbol");
        }
        else
        {   nxtSymbolId   +=   1;
           symbNdx[token]   =   cast(SymbolId)symbols.length;
           symbols   ~=   new   Symbol(token);
        }
     }

 }

 ++++++++++++++++++++++++ in a new file ++++++++++++++++++++++++

 import	symbol;
 SymbolId   makeSym(inout   Symbols   symbols,   in   Token   phrase)
 {   symbols.append(phrase);
     //return   symbols[cast(Token)phrase];
     return   symbols.optIndex(phrase);
 }

Jun 23 2005
parent Charles Hixson <charleshixsn earthlink.net> writes:
Regan Heath wrote:
 On Thu, 23 Jun 2005 17:00:25 -0700, Charles Hixson  
 <charleshixsn earthlink.net> wrote:
 OK, here it is.  Note that I had to define append rather than using  
 optCatAssign, and I have to call optIndex as a function rather than  
 using [] access.  There seem to be type problems that I don't  
 understand.  (Sample use at the end.)

It's opIndex, not optIndex, that's why it wasn't working.
 I haven't tested the code yet beyond getting it to compile, but it's  
 hardly a complete application.

Missing was TokenException (I defined one). I'll see what I come up with, no promises :) Regan p.s. the code below is really weirdly formatted, extra double spaced everywhere.. was that intentional or a result of the NG?

spaces = one tab. (I pasted that into the email, and then did a global replace of tabs with 3 spaces...not good, but the starts of lines should be OK.) My guess was that most of the lines were too long, and the messaging processes split the lines somewhere along the path. (TokenException doesn't do anything special except say "This is a token exception with the following message: xxxxx" ... only of course, not literally that. Nearly anything you defined it as should work adequately.)
Jun 23 2005
prev sibling next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Thu, 23 Jun 2005 17:00:25 -0700, Charles Hixson wrote:


[snip]
 OK, here it is.  Note that I had to define append rather than 
 using optCatAssign, and I have to call optIndex as a function 
 rather than using [] access.

Should be "op" rather than "opt". However the opCatAssign() will not work until Walter allows us to concatenate things that are not arrays. If you define opCatAssign() and then use "x ~= y" where 'y' is not an array or an element of 'x', the compiler complains. Anyhow, here is the result of my playing around with your code. I added opIndex(int) to make using symbols[int] easier, and a Count() method. <code for file symbol.d> typedef uint SymbolId; typedef uint IndexId; typedef char[] Token; class SymbolException { char[] m_msg; this(char[] msg) { m_msg = msg.dup; } } class Symbols { protected: struct Symbol { Token token; SymbolId symbolId; bit arithme; bit defined; float value; IndexId indexId; void Init(Token t) { token = t; symbolId = nxtSymbolId; } } static SymbolId nxtSymbolId = 0; Symbol[] lSymbolList; /* note that the symbNdx hash table can be rebuilt as needed from the symbols array. Thus it need not be saved. */ SymbolId[Token] symbNdx; void AddSymbol(Token pToken) { nxtSymbolId += 1; symbNdx[pToken] = nxtSymbolId; lSymbolList.length = lSymbolList.length + 1; lSymbolList[$-1].Init(pToken); } invariant { // Make sure the index is kept current assert (lSymbolList.length == symbNdx.length); } bit search(Symbol symbol) { return search(symbol.token); } public: this () { } bool search(SymbolId pSymbolId) { if (pSymbolId >= nxtSymbolId) return false; if (pSymbolId >= lSymbolList.length) return false; assert(lSymbolList[pSymbolId].symbolId == pSymbolId); return true; } bool search(Token token) { return (token in symbNdx) is null ? false : true; } Token opIndex(SymbolId symbolId) { if (symbolId >= lSymbolList.length) return null; return lSymbolList[symbolId].token; } SymbolId opIndex(Token token) { assert (token !is null); return symbNdx[token]; } Token opIndex(int pIdx) { assert(pIdx >= 0 && pIdx < lSymbolList.length); return lSymbolList[pIdx].token; } SymbolId append(Token token) in { assert (token !is null); } body { Symbol symb; if (search (token) ) { // do we really want to allow symbols to be redefined? throw new SymbolException("attempt to redefine existing symbol"); } AddSymbol(token); return nxtSymbolId; } int Count() { return lSymbolList.length; } } </code> <code for test.d> import std.stdio; import symbol; void main() { Symbols lBase = new Symbols; lBase.append(cast(Token)"if"); lBase.append(cast(Token)"static"); lBase.append(cast(Token)"static if"); for(int i = 0; i < lBase.Count; i++) { writefln("Symbol id %d: '%s'", i, lBase[i]); } }</code> -- Derek Melbourne, Australia 24/06/2005 11:18:46 AM
Jun 23 2005
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
Derek Parnell wrote:
 On Thu, 23 Jun 2005 17:00:25 -0700, Charles Hixson wrote:
 
 
 [snip]
 OK, here it is.  Note that I had to define append rather than 
 using optCatAssign, and I have to call optIndex as a function 
 rather than using [] access.

Should be "op" rather than "opt". However the opCatAssign() will not work until Walter allows us to concatenate things that are not arrays. If you define opCatAssign() and then use "x ~= y" where 'y' is not an array or an element of 'x', the compiler complains. [snip]

Thanks much for the analysis. At least that tells me: 1) How to fix MY mistake and 2) Why the thing that wasn't my mistake didn't work. I do hope that SOME better way to append to a container class soon becomes available. opCatAssign seemed the most reasonable, but if not that, then some other. Otherwise user container classes will remain...kludgy. (You don't happen to know if allowing this is planned for the future, do you?)
Jun 24 2005
next sibling parent Derek Parnell <derek psych.ward> writes:
On Fri, 24 Jun 2005 00:00:19 -0700, Charles Hixson wrote:

 Derek Parnell wrote:
 ... the opCatAssign() will not work
 until Walter allows us to concatenate things that are not arrays. If you
 define opCatAssign() and then use "x ~= y" where 'y' is not an array or an
 element of 'x', the compiler complains.


 ...  (You don't happen to know if allowing this is 
 planned for the future, do you?)

No I don't. It seems a sensible idea to a mere mortal like myself but Walter doesn't always see things the same way that I do ;-) In my opinion, the general case of ... <classinstance> ~= <expression> should call <classinstance>.opCatAssign( <expression> ) if there is a matching member defined. This should also apply to structs as well. My rationale is that it if such a member is defined then the class (or struct) knows what to do with the <expression> so the compiler should just let it do its thing. I hope that this is just an oversight and will be fixed very soon. -- Derek Melbourne, Australia 24/06/2005 5:12:01 PM
Jun 24 2005
prev sibling parent reply Mike Parker <aldacron71 yahoo.com> writes:
Charles Hixson wrote:

 other.  Otherwise user container classes will remain...kludgy.  (You 
 don't happen to know if allowing this is planned for the future, do you?)
 

What's so kludgy? I don't see any difference between: x ~= y and x.append(y); Less typing with the operator, particularly for chaining, but the same result either way. I prefer the latter, actually. To me the ~ operator in D means 'concat 2 arrays'. Once you start allowing it to be overloaded, it could mean anything. Then you wind up with cryptic code where you constantly have to look up the overide to make sure it really is appending/concatting and not doing something funky. It's like when people use the * operator with two vectors to carry out a dot product. Always throws me off. I would be happy if Walter did away with operator overloading altogether, but that's just wishful thinking :)
Jun 24 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Fri, 24 Jun 2005 16:45:49 +0900, Mike Parker wrote:

 Charles Hixson wrote:
 
 other.  Otherwise user container classes will remain...kludgy.  (You 
 don't happen to know if allowing this is planned for the future, do you?)
 

What's so kludgy? I don't see any difference between: x ~= y and x.append(y); Less typing with the operator, particularly for chaining, but the same result either way. I prefer the latter, actually. To me the ~ operator in D means 'concat 2 arrays'.

I understand your point of view. To me "~" means "concat 2 things together".
 Once you start allowing it to be 
 overloaded, it could mean anything. Then you wind up with cryptic code 
 where you constantly have to look up the overide to make sure it really 
 is appending/concatting and not doing something funky. It's like when 
 people use the * operator with two vectors to carry out a dot product. 
 Always throws me off. I would be happy if Walter did away with operator 
 overloading altogether, but that's just wishful thinking :)

Yes, this is an issue with overloading operators, but on the other hand, how do you know that a function called 'append' is also not doing anything 'funky'? It might not even be appending. Its the same argument really. -- Derek Melbourne, Australia 24/06/2005 6:52:24 PM
Jun 24 2005
parent Mike Parker <aldacron71 yahoo.com> writes:
Derek Parnell wrote:

 Yes, this is an issue with overloading operators, but on the other hand,
 how do you know that a function called 'append' is also not doing anything
 'funky'? It might not even be appending. Its the same argument really.
 

trained to recognize it as a specific functions. '+' generally means 'add' and '-' generally means 'subtract'. This is built in to the language do fundamentally never changes. Function names and implementations *do* vary from API to API and generally require that you read the documentation and/or source to completely understand what any given function does. So when I'm skimming source, a '+' operator registers as 'addition' automatically and the eyes move on, but a function named 'add' registers no differently than a function named 'googleyfoobob' - both being functions, they will definitely stand out if I don't already know exactly what they do, particularly when debugging.
Jun 24 2005
prev sibling parent reply "Regan Heath" <regan netwin.co.nz> writes:
After a brief look I'm not quite sure where to start.

I see Symbols  (the container class)
I see Symbol   (created to hold a Token, and SymbolId)
I see Token    (an object)
I see SymbolId (ever incrementing, always unique id for a Symbol)
I see IndexId  (not used?)

You said "But I'd need to write it several times", what parts change for  
the next time?

Regan
Jun 23 2005
parent Charles Hixson <charleshixsn earthlink.net> writes:
Regan Heath wrote:
 After a brief look I'm not quite sure where to start.
 
 I see Symbols  (the container class)
 I see Symbol   (created to hold a Token, and SymbolId)
 I see Token    (an object)
 I see SymbolId (ever incrementing, always unique id for a Symbol)
 I see IndexId  (not used?)
 
 You said "But I'd need to write it several times", what parts change 
 for  the next time?
 
 Regan

sure whatall as I'm still translating (and understanding) the original program. Certainly I won't be doing things quite the same way, as the original includes a manually implemented hash table and tree structure, and there are pointers all over the place. (I have a fierce distaste for having to deal with pointers. That's the compiler's job!) It also includes storage management without including garbage collection. I'm certain that parts of what I'm not understanding have to do with that. Etc. As near as I can tell the guy who wrote it was more a professor of Computer Science specializing in AI than a programmer. I feel certain that Ada COULD be done more neatly. (OTOH, without understanding exactly what he's doing in places, this is a bit of a non-humble analysis...but, e.g., he implemented his own variable length strings claiming that Ada didn't provide them. But perhaps they were added with Ada95, and he was writing for Ada 198x.) Anyway understanding the program is one challenge, and translating it into a modern decent language is another. And when I get done I'll have a toy backward chaining Expert System Shell. (I'll probably also change the syntax of the rules...but first I need to understand what he was doing with them originally...and that requires understanding the program. :) I'm finding the combination to be quite an interesting challenge.) P.S.: SymbolId, TokenId, PredicateId, RuleId, etc. are all my idea. The original used pointers in these places, but I want something that I can reasonably store in a database. Id's are permanent, memory locations are transient. This means that it's going to be a bit difficult to forget things, since I won't be able to depend on a garbage collector, but it's worth the price to be able to checkpoint dump a process, and then resume later without worrying about relocation in memory.
Jun 23 2005
prev sibling parent reply Chris Sauls <ibisbasenji gmail.com> writes:
Charles Hixson wrote:
    Type GoalRange is Integer range 0...MaxGoal;
    Type Goals is array (GoalRange) of Goal;
 
 then it's a compilation error if you index the array with a variable of 
 any type other than GoalRange.  This isn't necessary in order to 

Couldn't you just use a static array? Or am I missing something? -- Chris Sauls
Jun 22 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Wed, 22 Jun 2005 02:16:15 -0500, Chris Sauls wrote:

 Charles Hixson wrote:
    Type GoalRange is Integer range 0...MaxGoal;
    Type Goals is array (GoalRange) of Goal;
 
 then it's a compilation error if you index the array with a variable of 
 any type other than GoalRange.  This isn't necessary in order to 

Couldn't you just use a static array? Or am I missing something?

It would be used in situations like this ... typedef int WidgetId; typedef int Dimension; class Widget { . . . } Widget[cast(WidgetId)] KnownWidgets; Dimension x,y,z; . . . KnownWidgets[ x ].Hide(); // This should fail as it's index // is a 'Dimension' and not a 'WidgetId' -- Derek Parnell Melbourne, Australia 22/06/2005 7:33:51 PM
Jun 22 2005
parent Chris Sauls <ibisbasenji gmail.com> writes:
Derek Parnell wrote:
    Widget[cast(WidgetId)] KnownWidgets;
    Dimension x,y,z;
    . . .
    KnownWidgets[ x ].Hide(); // This should fail as it's index
                              // is a 'Dimension' and not a 'WidgetId'

Okay, I get it now... odd, but I guess its like another kind of contract. -- Chris Sauls
Jun 22 2005
prev sibling parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 20 Jun 2005 13:34:14 -0700, Charles Hixson wrote:

 Jarrett Billingsley wrote:
 "Charles Hixson" <charleshixsn earthlink.net> wrote in message 
 news:d950du$2u4c$1 digitaldaemon.com...
 
Does:
typedef int MyType;
char[MyType] val;

result in val being an associative array, rather than an arrays whose 
indicies are typechecked to be instances of MyType?

Yes. Any time you put _any_ kind of type inside the brackets, it's an AA. This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."

Unfortunately, what I wanted wasn't a sparse array, but an array that required it's indexes to be a particular type... O, well. At other times I want sparse arrays...so that's all to the good. Any suggestions as to how to require indexes to be of a particular type? (All I can think of is building a class, and implementing optAssign, etc.)

Maybe a struct might be useful ... struct arrtype { int x; } void main() { char[][ arrtype ] c; arrtype a,b; a.x = 1; b.x = 2; c[a] = "one"; c[b] = "two"; } -- Derek Parnell Melbourne, Australia 21/06/2005 8:04:42 AM
Jun 20 2005
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
Derek Parnell wrote:
 On Mon, 20 Jun 2005 13:34:14 -0700, Charles Hixson wrote:
 
 Jarrett Billingsley wrote:
 "Charles Hixson" <charleshixsn earthlink.net> wrote in message 
 news:d950du$2u4c$1 digitaldaemon.com...

 Does:
 typedef int MyType;
 char[MyType] val;

 result in val being an associative array, rather than an arrays whose 
 indicies are typechecked to be instances of MyType?

Yes. Any time you put _any_ kind of type inside the brackets, it's an AA. This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."

Unfortunately, what I wanted wasn't a sparse array, but an array that required it's indexes to be a particular type... O, well. At other times I want sparse arrays...so that's all to the good. Any suggestions as to how to require indexes to be of a particular type? (All I can think of is building a class, and implementing optAssign, etc.)

Maybe a struct might be useful ... struct arrtype { int x; } void main() { char[][ arrtype ] c; arrtype a,b; a.x = 1; b.x = 2; c[a] = "one"; c[b] = "two"; }

No, I think what I need to do (if I decide it's worth it) is create a class and implement opIndex, opIndexAssign, and possibly opSlice (two versions). That would (apparently?) allow me to specify the index type required...but that's a bit heavy duty just to implement a bit of type checking...so I'll probably skip that unless I find an easier way, or unless I find another reason to create it as a class.
Jun 21 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Tue, 21 Jun 2005 20:37:44 -0700, Charles Hixson wrote:

 Derek Parnell wrote:
 On Mon, 20 Jun 2005 13:34:14 -0700, Charles Hixson wrote:
 
 Jarrett Billingsley wrote:
 "Charles Hixson" <charleshixsn earthlink.net> wrote in message 
 news:d950du$2u4c$1 digitaldaemon.com...

 Does:
 typedef int MyType;
 char[MyType] val;

 result in val being an associative array, rather than an arrays whose 
 indicies are typechecked to be instances of MyType?

Yes. Any time you put _any_ kind of type inside the brackets, it's an AA. This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."

Unfortunately, what I wanted wasn't a sparse array, but an array that required it's indexes to be a particular type... O, well. At other times I want sparse arrays...so that's all to the good. Any suggestions as to how to require indexes to be of a particular type? (All I can think of is building a class, and implementing optAssign, etc.)

Maybe a struct might be useful ... struct arrtype { int x; } void main() { char[][ arrtype ] c; arrtype a,b; a.x = 1; b.x = 2; c[a] = "one"; c[b] = "two"; }

No, I think what I need to do (if I decide it's worth it) is create a class and implement opIndex, opIndexAssign, and possibly opSlice (two versions). That would (apparently?) allow me to specify the index type required...but that's a bit heavy duty just to implement a bit of type checking...so I'll probably skip that unless I find an easier way, or unless I find another reason to create it as a class.

Sorry, I misunderstood. So you want a standard array, that is one in which the index is an offset from the start of the array, but you want to specify that only certain types of integers are allowed as indexes in array references. Sounds like a useful idea; a natural extension of static type checking. -- Derek Melbourne, Australia 22/06/2005 1:52:49 PM
Jun 21 2005
parent Charles Hixson <charleshixsn earthlink.net> writes:
Derek Parnell wrote:
 On Tue, 21 Jun 2005 20:37:44 -0700, Charles Hixson wrote:
 
 Derek Parnell wrote:
 On Mon, 20 Jun 2005 13:34:14 -0700, Charles Hixson wrote:

 Jarrett Billingsley wrote:
 "Charles Hixson" <charleshixsn earthlink.net> wrote in message 
 news:d950du$2u4c$1 digitaldaemon.com...

 Does:
 typedef int MyType;
 char[MyType] val;

 result in val being an associative array, rather than an arrays whose 
 indicies are typechecked to be instances of MyType?

This works too: char[int] val; val is an AA of chars indexed by ints. I think an AA with an int key is usually called a "sparse array."

Unfortunately, what I wanted wasn't a sparse array, but an array that required it's indexes to be a particular type... O, well. At other times I want sparse arrays...so that's all to the good. Any suggestions as to how to require indexes to be of a particular type? (All I can think of is building a class, and implementing optAssign, etc.)

struct arrtype { int x; } void main() { char[][ arrtype ] c; arrtype a,b; a.x = 1; b.x = 2; c[a] = "one"; c[b] = "two"; }

No, I think what I need to do (if I decide it's worth it) is create a class and implement opIndex, opIndexAssign, and possibly opSlice (two versions). That would (apparently?) allow me to specify the index type required...but that's a bit heavy duty just to implement a bit of type checking...so I'll probably skip that unless I find an easier way, or unless I find another reason to create it as a class.

Sorry, I misunderstood. So you want a standard array, that is one in which the index is an offset from the start of the array, but you want to specify that only certain types of integers are allowed as indexes in array references. Sounds like a useful idea; a natural extension of static type checking.

agree that hash tables are a more important use for the syntax. Up until now I'd been confused about just WHAT would happen if I declared an array with an integer type, possibly partially BECAUSE Ada used it for type checking...which seems to me a straight-forward interpretation of the syntax, just not the most useful one. Hash tables have more general utility, but error checking is also high priority...it would be nice to have BOTH. Unfortunately, just how to do it isn't terribly clear. Possibly range types are the answer. This would require simple syntax to specify open-ended (well, sort of) ranges. Then one could adopt the convention that arrays indexed by a range were normal arrays with a range index. (But then how would one make a hash table over a range?) One obvious answer is to adopt a new keyword in the special limited context of array declarations, thus: typedef short Entry; int[indexed by Entry] checkedItems; This would work, and is clear, but requires the new keyword "indexed by" within the context of an array declaration. This isn't as bad as it might be, as it wouldn't break any existing code...but it does make things more complicated.
Jun 22 2005