|
From: Adam Beneschan on 4 Apr 2008 17:15 On Apr 4, 2:09 pm, Adam Beneschan <a...(a)irvine.com> wrote: > On Apr 4, 9:10 am, Pascal Obry <pas...(a)obry.net> wrote: > > > > Sorting out string handling out would be nice, too. > > > Probably something to do in this area I agree. > > OK, this is *really* beating a dead horse, but... > > When I read this and was thinking randomly about Ada's string > handling, I got to wondering why Bounded_Strings was defined as a > generic I got sloppy with the names, of course. The package name is Ada.Strings.Bounded, and the generic I'm referring to is the nested generic package Generic_Bounded_Length. Please imagine the appropriate substitutions in the rest of my post. Hopefully you can all tell what I meant. I guess that tells you how often I use this. -- Adam
From: Gautier on 5 Apr 2008 00:39 Adam Beneschan: > When I read this and was thinking randomly about Ada's string > handling, I got to wondering why Bounded_Strings was defined as a > generic, rather than declaring a discriminated type with the maximum > length as the discriminant. Do you mean something like that ? ------------------------------------------------------------------------------ -- File: BorString.ads -- Description: Variable-size, bounded strings as in early Borland Pascals -- Essentially for quick portability purposes. -- Date / Version: 14-May-2001 ; 4-May-2000 -- Author: Gautier de Montmollin -- Portability: Full: pure Ada 83. Nearest Ada 95+ package: the -- generic Ada.Strings.Bounded . ------------------------------------------------------------------------------ package BorStrings is type BorString( maxlength: positive ) is private; -- Idea: you can convert to string for _functional_ manipulations function To_String( b:BorString ) return String; -- ... then, put the result in a BorString if needed procedure Put( b : in out BorString; c: Character ); procedure Put( b : in out BorString; s: String ); procedure Put( bd: in out BorString; bs: BorString ); -- Note: with the "&" concatenators defined below, you can do it -- straigthforward ! -- * Procedures and functions that are in Turbo Pascal and later: -- Concat Copy Delete Insert Length Pos -- * We add RPos for searching a string from the _right_ -- Concat: use the "&" operator instead! NB: TP has "+" function Copy(b: BorString; index: Integer; count: Integer) return String; procedure Delete( b: in out BorString; index: Positive; count: Positive); procedure Insert( source: String; b: in out BorString; index: Integer); procedure Insert( source: BorString; b: in out BorString; index: Integer); function Length( b: BorString ) return Natural; function Pos( substr: String; b: BorString) return Natural; function RPos( substr: String; b: BorString) return Natural; -- "&" operators returning a BorString of _same_ maxlength as the input -- so you can write b:= b & " " or b:= "[" & b & "]" ! function "&" ( c: Character; b: BorString) return BorString; function "&" ( s: String; b: BorString) return BorString; function "&" ( b: BorString; c: Character) return BorString; function "&" ( b: BorString; s: String) return BorString; -- same, returning strings (experimental: can cause ambiguities) function "&" ( c: Character; b: BorString) return String; function "&" ( s: String; b: BorString) return String; function "&" ( b: BorString; c: Character) return String; function "&" ( b: BorString; s: String) return String; function Eq ( b1,b2: BorString ) return Boolean; function Eq ( b1: BorString; s2: String ) return Boolean; string_overflow: exception; pragma Inline(To_String); private type BorString( maxlength: positive ) is record length: Natural:= 0; s: String( 1..maxlength ); end record; -- NB: length allows longer strings than the "s[0]" in T/B-Pascal end BorStrings; ______________________________________________________________ Gautier -- http://www.mysunrise.ch/users/gdm/index.htm Ada programming -- http://www.mysunrise.ch/users/gdm/gsoft.htm NB: For a direct answer, e-mail address on the Web site!
From: Pascal Obry on 5 Apr 2008 05:43 Gautier, > Do you mean something like that ? No quite as: B1 : BorString (10); B2 : BorString (20); B1 := B2; -- will raises constraint error With Unbounded_String we are close to something "usable". U1 : Unbounded_String; U2 : Unbounded_String; U1 := U2; Works fine! But then it becomes a bit messy when converting back and forth with the string type. U1 := To_Unbounded_String ("whatever"); Put_Line (To_String (U1)); Not a big deal, but if we can find a nice way to tell that such routine must be used for conversion between type it will be quite handy. type Unbounded_String is ...; function To_String (U : Unbounded_String) return String; for Unbounded_String'Conversion (String) use To_String; Just to get the idea, then one could write: Put_Line (U1); Of course this raises some questions: What to do if we have Put_Line defined for String and Unbounded_String? Which version gets called? .... Anyway that's just some wild thoughts :) Pascal. -- --|------------------------------------------------------ --| Pascal Obry Team-Ada Member --| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE --|------------------------------------------------------ --| http://www.obry.net --| "The best way to travel is by means of imagination" --| --| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595
From: Dmitry A. Kazakov on 5 Apr 2008 06:10 On Sat, 05 Apr 2008 11:43:39 +0200, Pascal Obry wrote: > Works fine! But then it becomes a bit messy when converting back and > forth with the string type. > > U1 := To_Unbounded_String ("whatever"); > > Put_Line (To_String (U1)); > > Not a big deal, but if we can find a nice way to tell that such routine > must be used for conversion between type it will be quite handy. > > type Unbounded_String is ...; > > function To_String (U : Unbounded_String) return String; > > for Unbounded_String'Conversion (String) use To_String; No, that would be a can of worms. Arbitrary type conversions automatically applied is a mess. Below you immediately spot the problem of conversions preferences. Because conversions are arbitrary, there is no any order defined on the types to make a choice. What is actually needed is to say that Unbounded_String is a member of String'Class and you wanted to inherit everything form String. The implementation of inheritance (by the compiler) will require you to provide two *private* conversion functions when the types are untagged. Note that you need two conversions: a forward conversion for in-parameters and a backward conversion for out-ones. In out parameters will use both (copy-in, copy-out). For tagged [actually, by-reference] types the compiler can generate conversions because they are necessarily view conversions. > Just to get the idea, then one could write: > > Put_Line (U1); > > Of course this raises some questions: > > What to do if we have Put_Line defined for String and > Unbounded_String? Which version gets called? It will one of Unbounded_String, because that will be an override. Note though, that Put_Line (File, String) will open further questions. Is it primitive in File or in String? Clearly it should be in both. This is how multiple dispatch issue comes in. > Anyway that's just some wild thoughts :) It is not wild, it is how Ada types system should be completed. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: Gautier on 5 Apr 2008 07:36
Pascal Obry wrote: .... > With Unbounded_String we are close to something "usable". That's clear. I think Adam's question was really specific to the bounded strings. Unbounded_String is the most comfortable and the safest, but needs dynamic allocation behind the scenes, which can be a handicap on some special situations (performance-critical, systems without dynamic allocation,...). > U1 : Unbounded_String; > U2 : Unbounded_String; > > U1 := U2; > > Works fine! But then it becomes a bit messy when converting back and > forth with the string type. > > U1 := To_Unbounded_String ("whatever"); > > Put_Line (To_String (U1)); > > Not a big deal, but if we can find a nice way to tell that such routine > must be used for conversion between type it will be quite handy. > > type Unbounded_String is ...; > > function To_String (U : Unbounded_String) return String; > > for Unbounded_String'Conversion (String) use To_String; > > Just to get the idea, then one could write: > > Put_Line (U1); > > Of course this raises some questions: > > What to do if we have Put_Line defined for String and > Unbounded_String? Which version gets called? > > ... > > Anyway that's just some wild thoughts :) I agree with Dmitry that it would lead to confusing situations, something that Ada normally tries to avoid... What I'm doing to make life easier is to paste the following lines in my sources function S (Source : Ada.Strings.Unbounded.Unbounded_String) return String renames Ada.Strings.Unbounded.To_String; function U (Source : String) return Ada.Strings.Unbounded.Unbounded_String renames Ada.Strings.Unbounded.To_Unbounded_String; After the sources only need short S(...)'s and U(...)'s which are ok to me: external_packer: array(External) of Unbounded_String:= ( U("zip.exe"), U("7z.exe"), U("kzip.exe") ); .... return "External: " & S(external_title(a)) & ", " & S(external_options(a)); .... e.name:= U(unique_name); ...., etc. etc. ______________________________________________________________ Gautier -- http://www.mysunrise.ch/users/gdm/index.htm Ada programming -- http://www.mysunrise.ch/users/gdm/gsoft.htm NB: For a direct answer, e-mail address on the Web site! |