From: Marek Janukowicz on
Hello everyone

I'm struggling with some design problems in my project. To explain them I
need to give some background on my project, so please bear with me.

I'm developing a library to wrap relational database records into Ada
objects (this kind of libraries are usually called "ORMs"). Generally I need
following entities:
- some type corresponding to database table (I called it "Model"). It's
instances will hold records from that table, so it needs something to hold
database column values as attributes. Operations generally need to be
overridable.
- something to map relationships between tables (associations)

For Model I use a tagged type wrapped into generic package:
generic
Tbl_Name : String;
type Attribute_Type is (<>);
type Attribute_Type_Array is array (Attribute_Type range <>) of
Attribute_Type_Type;
Attribute_Types : Attribute_Type_Array;
package Dar.Models.Base is

type Model is abstract tagged limited record
....

For associations I also use a generic package:
generic
with package Source_Model is new Dar.Models.Base(<>);
with package Target_Model is new Dar.Models.Base(<>);
Foreign_Key : String;
package Dar.Models.Associations is
function Find
....


Here's where the trouble begins. Those Model subtypes tend to have quite a
lot of custom logic, some operations overriden etc. and I can't add this to
generic package instantiation, so I instantiate Dar.Models.Base inside
another package:

package Dar_Test.Models.Users is
type Attribute_Type is (Id, Username, Email);
type Attribute_Type_Array is array (Attribute_Type range <>) of
Dar.Models.Attribute_Type_Type;
package Base is new Dar.Models.Base(
Tbl_Name => "authors",
Attribute_Type => Attribute_Type,
Attribute_Type_Array => Attribute_Type_Array,
Attribute_Types => (
Id => Attr_Integer,
Username => Attr_String,
Email => Attr_String
)
);
(some additional operations)
...

What I don't like is that I have additional operations in Users package, but
builtin operations in Users.Base (I want to make the design clean for
programmers using my library). I don't like parametrizing Associations with
Base instantiation. I think having just a tagged type (without a generic
package Dar.Models.Base) and extending it would be better, but I don't know
how to parametrize it with Attribute_Type type.

I hope my description is not too vague. If you have any thoughts or think my
approach is totally wrong please share your thoughts.

Two additional (small) questions:
1. I'd like to replace type Attribute_Type_Array is array (Attribute_Type
range <>) of Attribute_Type_Type in Dar.Models.Base specification with ...
array (Attribute_Type'Range) ... to make sure full range of Attribute_Type
is specified, but the compiler complains. Is there any other way to ensure
that?
2. I have a type Attribute_Type_Type used to specify types of attributes
(Integer, Date, String etc.). I then have a variant record:
type Attribute_Value( Attr_Type : Attribute_Type_Type ) is
record
case Attr_Type is
when Attr_Date =>
Date_Value : APQ_Date;
when Attr_Time =>
Time_Value : APQ_Time;
...
Is there any way to use builtin types here instead of Attr_Date,
Attr_Integer, etc? Note that I need to specify type of each attribute in one
array.

Thanks in advance for reading my lengthy post :)
--
Marek Janukowicz

--- news://freenews.netfront.net/ - complaints: news(a)netfront.net ---
From: Simon Wright on
Marek Janukowicz <marek(a)janukowicz.net> writes:

> Hello everyone
>
> I'm struggling with some design problems in my project. To explain them I
> need to give some background on my project, so please bear with me.
>
> I'm developing a library to wrap relational database records into Ada
> objects (this kind of libraries are usually called "ORMs"). Generally I need
> following entities:
> - some type corresponding to database table (I called it "Model"). It's
> instances will hold records from that table, so it needs something to hold
> database column values as attributes. Operations generally need to be
> overridable.
> - something to map relationships between tables (associations)
>
> For Model I use a tagged type wrapped into generic package:
> generic
> Tbl_Name : String;
> type Attribute_Type is (<>);
> type Attribute_Type_Array is array (Attribute_Type range <>) of

Does this have to be an unconstrained array? If it wasn't, you wouldn't
need to worry about whether Attribute_Types covered the range of
Attribute_Type.

> Attribute_Type_Type;
> Attribute_Types : Attribute_Type_Array;
> package Dar.Models.Base is
>
> type Model is abstract tagged limited record

type Model is new Abstract_Base with ...

> ...
>
> For associations I also use a generic package:
> generic
> with package Source_Model is new Dar.Models.Base(<>);
> with package Target_Model is new Dar.Models.Base(<>);
> Foreign_Key : String;
> package Dar.Models.Associations is
> function Find
> ...

.... then the association can be between objects of type
Abstract_Base_Class'Class (though I don't see how you'd express the
actual relationship, not clear how Foreign_Key enters the picture).

>
>
> Here's where the trouble begins. Those Model subtypes tend to have quite a
> lot of custom logic, some operations overriden etc. and I can't add this to
> generic package instantiation, so I instantiate Dar.Models.Base inside
> another package:
>
> package Dar_Test.Models.Users is
> type Attribute_Type is (Id, Username, Email);
> type Attribute_Type_Array is array (Attribute_Type range <>) of
> Dar.Models.Attribute_Type_Type;
> package Base is new Dar.Models.Base(
> Tbl_Name => "authors",
> Attribute_Type => Attribute_Type,
> Attribute_Type_Array => Attribute_Type_Array,
> Attribute_Types => (
> Id => Attr_Integer,
> Username => Attr_String,
> Email => Attr_String
> )
> );
> (some additional operations)
> ...
>
> What I don't like is that I have additional operations in Users package, but
> builtin operations in Users.Base (I want to make the design clean for
> programmers using my library). I don't like parametrizing Associations with
> Base instantiation. I think having just a tagged type (without a generic
> package Dar.Models.Base) and extending it would be better, but I don't know
> how to parametrize it with Attribute_Type type.
>
> I hope my description is not too vague. If you have any thoughts or think my
> approach is totally wrong please share your thoughts.
>
> Two additional (small) questions:
> 1. I'd like to replace type Attribute_Type_Array is array (Attribute_Type
> range <>) of Attribute_Type_Type in Dar.Models.Base specification with ...
> array (Attribute_Type'Range) ... to make sure full range of Attribute_Type
> is specified, but the compiler complains. Is there any other way to ensure
> that?

See above for suggestion. And why not just "array (Attribute_Type)"?

> 2. I have a type Attribute_Type_Type used to specify types of attributes
> (Integer, Date, String etc.). I then have a variant record:
> type Attribute_Value( Attr_Type : Attribute_Type_Type ) is
> record
> case Attr_Type is
> when Attr_Date =>
> Date_Value : APQ_Date;
> when Attr_Time =>
> Time_Value : APQ_Time;
> ...
> Is there any way to use builtin types here instead of Attr_Date,
> Attr_Integer, etc? Note that I need to specify type of each attribute in one
> array.

I don't believe so.

As a side note I really dislike the name Attribute_Type_Type. It seems
to me that what you've called Attribute_Type is much more like a Name
than a Type.
From: Marek Janukowicz on
Simon Wright wrote:
>> For Model I use a tagged type wrapped into generic package:
>> generic
>> Tbl_Name : String;
>> type Attribute_Type is (<>);
>> type Attribute_Type_Array is array (Attribute_Type range <>) of
>
> Does this have to be an unconstrained array? If it wasn't, you wouldn't
> need to worry about whether Attribute_Types covered the range of
> Attribute_Type.

The only reason it was an unconstrained array is that my Ada skills are
extremely poor and I didn't know it would work this way :) I'm a bit lost in
this subject in general: could anyone tell me the exact difference between:
- array (Attribute_Type)
- array (Attribute_Type range <>)
- array (Attribute_Type'Range)


>> Attribute_Type_Type;
>> Attribute_Types : Attribute_Type_Array;
>> package Dar.Models.Base is
>>
>> type Model is abstract tagged limited record
>
> type Model is new Abstract_Base with ...
>
>> ...
>>
>> For associations I also use a generic package:
>> generic
>> with package Source_Model is new Dar.Models.Base(<>);
>> with package Target_Model is new Dar.Models.Base(<>);
>> Foreign_Key : String;
>> package Dar.Models.Associations is
>> function Find
>> ...
>
> ... then the association can be between objects of type
> Abstract_Base_Class'Class (though I don't see how you'd express the
> actual relationship, not clear how Foreign_Key enters the picture).

That's how I really have it implemented, didn't want to go that much into
the details. Generally, I need to figure out what's really my problem here
and then ask again :)

>> 2. I have a type Attribute_Type_Type used to specify types of attributes
>> (Integer, Date, String etc.). I then have a variant record:
>> type Attribute_Value( Attr_Type : Attribute_Type_Type ) is
>> record
>> case Attr_Type is
>> when Attr_Date =>
>> Date_Value : APQ_Date;
>> when Attr_Time =>
>> Time_Value : APQ_Time;
>> ...
>> Is there any way to use builtin types here instead of Attr_Date,
>> Attr_Integer, etc? Note that I need to specify type of each attribute in
>> one array.
>
> I don't believe so.
>
> As a side note I really dislike the name Attribute_Type_Type. It seems
> to me that what you've called Attribute_Type is much more like a Name
> than a Type.

Yeah, you might be right on that. I still need to find out what a good
naming convention would be. I wouldn't like to use:

type Attribute_Name_Type is (Id, Username, ...)

but if I call the type Attribute_Name I'll have problems naming variables of
that type (because Attribute_Name seems to be the best name for them as
well).

That's one of the things I dislike in Ada - everything (types, variables,
packages, operations) follows exactly the same naming convention and doesn't
use any special character/whatever to distinguish between them, so you run
out of good names in no time...

--
Marek Janukowicz

--- news://freenews.netfront.net/ - complaints: news(a)netfront.net ---
From: Simon Wright on
Marek Janukowicz <marek(a)janukowicz.net> writes:

> Simon Wright wrote:

> I'm a bit lost in
> this subject in general: could anyone tell me the exact difference between:
> - array (Attribute_Type)
This is an array indexed by the full range of the index type.

> - array (Attribute_Type range <>)
This is an array indexed by some contiguous subset of the full index
type.
If Attribute_Type was (A, B, C) any particular array could have no
elements or elements (A), (B), (C), (A, B), (B, C), (A, B, C) .. but not
elements (A, C).

> - array (Attribute_Type'Range)
This isn't allowed in a generic formal part.

>> As a side note I really dislike the name Attribute_Type_Type. It seems
>> to me that what you've called Attribute_Type is much more like a Name
>> than a Type.
>
> Yeah, you might be right on that. I still need to find out what a good
> naming convention would be. I wouldn't like to use:
>
> type Attribute_Name_Type is (Id, Username, ...)
>
> but if I call the type Attribute_Name I'll have problems naming variables of
> that type (because Attribute_Name seems to be the best name for them as
> well).

Maybe inserting another concept would help? Tables <have Columns which>
have Attributes. If you have table names, why not column names? Could
Column or perhaps Component be described by a record structure
(name, kind, ...)?

> That's one of the things I dislike in Ada - everything (types, variables,
> packages, operations) follows exactly the same naming convention and doesn't
> use any special character/whatever to distinguish between them, so you run
> out of good names in no time...

Kind and Sort can help, though (a) a bit English, maybe, (b) you'd still
need some convention about which is the more abstract.

Grady Booch used to use The_<type_name> for variables, which can get
rather ugly.

Use context -- I'd much rather write
procedure Send (M : Message);
than
procedure Send (The_Message : Message);
or, much worse,
procedure Send (Message_To_Send : Message);
From: Jeffrey R. Carter on
On 06/30/2010 10:57 PM, Simon Wright wrote:
>
> Use context -- I'd much rather write
> procedure Send (M : Message);
> than
> procedure Send (The_Message : Message);
> or, much worse,
> procedure Send (Message_To_Send : Message);

I don't really care which of these I write. But I'd much rather READ

Send (Message => ...);

than

Send (M => ...); -- Meaningless

or

Send (The_Message => ...); -- Prefixes decrease readability

or

Send (Message_To_Send => ...); -- "much worse"

so I'd probably write

procedure Send (Message : in Message_Info);

or something like that. More importantly, I'd decide that I want to read
"Message" as the formal parameter name 1st, and from there decide on my type name.

I understand that this requires thinking before coding, and so will never be
popular.

--
Jeff Carter
"My dear Mrs. Hemoglobin, when I first saw you, I
was so enamored with your beauty I ran to the basket,
jumped in, went down to the city, and bought myself a
wedding outfit."
Never Give a Sucker an Even Break
111
 |  Next  |  Last
Pages: 1 2
Prev: made me hate programming
Next: Mysql and gnade