Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Create a new String type 1

Status
Not open for further replies.

Griffyn

Programmer
Jul 11, 2002
1,077
AU
Hi all,

I'm still working away at this RPG, and have the need to create a new string type. Amongst my various objects I have string fields that will contain damage in the form of 'Fire:2D6,Edged:2D6+2'. For the curious, this means that the damage consists of 2-12 from fire, and 4-14 from an edged weapon. I want to force variables containing damage to go through separate methods ie
Code:
interface

type
  TDamage = type String;

  procedure Concise(var AStr: String); overload;
  procedure Concise(var AStr: TDamage); overload;

implementation

procedure Stuff;
var
  x : TDamage;
begin
  x := 'Fire:2D6,Edged:2D6+2,Fire:1D6';
  Concise(x);  // causes compilation error
end;
This code doesn't compile and causes an 'ambiguous overloaded call'. From the Delphi help file though, defining TDamage = type String should create it as a totally separate type, but it seems it's not enough.

Any clues on how I can do this? I know I could create a new TObject that can have handling built in and the rest, but I want to avoid having to Create and Destroy instances of TDamage.
 
did you try this:

Code:
procedure Stuff;
var
  x : String;
begin
  x := TDamage('Fire:2D6,Edged:2D6+2,Fire:1D6');
  Concise(x);  
end;



-----------------------------------------------------
What You See Is What You Get
Never underestimate tha powah of tha google!
 
This works for me in Delphi 7, which is I think what you want
Code:
type
  TDamage = type String;

procedure Concise(var AStr: String); overload;
begin
  Form1.Edit1.Text := AStr;
end;

procedure Concise(var AStr: TDamage); overload;
begin
  Form1.Edit1.Text := AStr;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  x: TDamage;
begin
  x :='Damage';
  Concise(x);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  x: String;
begin
  x  :='String';
  Concise(x);
end;

Andrew
Hampshire, UK
 
doh. rule number 1 kids: Don't post examples that are different from your problem.

Thanks whosrdaddy and Andrew, but while those examples work, my problem is slightly different. me bad.

Code:
interface

type
  TDamage = type String;

function Concise(AStr: String): String; overload;
function Concise(AStr: TDamage): TDamage; overload;

implementation

function Concise(AStr: String): String;
begin
end;

function Concise(AStr: TDamage): TDamage;
begin
end;

procedure Stuff;
var
  x, r : TDamage;
begin
  x := 'Fire:2D6,Edged:2D6+2,Fire:1D6';
  r := Concise(x);  // causes compilation error
end;

This is actually what I have in my code. I couldn't understand why Andrew posted what looked to be exactly the same code as what I posted earlier and it worked. And it does work on my system (Delphi 6). This example definitely does not work, and causes an ambiguous error. Sorry guys, try again?
 
Neither of your Concise functions set the result variable. The following code works in D7 (no compilation errors and the results are as expected). The form has two TButtons on it. Clicking Button1 shows the message String Concise. Clicking on Button2 shows the message TDamage Concise.
Code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

type
  TDamage = type String;

function Concise(var AStr: String): string; overload;
function Concise(var AStr: TDamage): TDamage; overload;

implementation

{$R *.dfm}

function Concise(var AStr: String): string; overload;
begin
  result := 'String Concise';
end;

function Concise(var AStr: TDamage): TDamage; overload;
begin
  result := 'TDamage Concise';
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  x: String;
begin
  x := 'Fire:2D6,Edged:2D6+2,Fire:1D6';
  ShowMessage ( Concise(x) );
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  x: TDamage;
begin
  x := 'Fire:2D6,Edged:2D6+2,Fire:1D6';
  ShowMessage ( Concise(x) );
end;

end.

Andrew
Hampshire, UK
 
So confusing. Thanks Andrew - yes your example does work. I'm confused why there's so little leeway in how this will work. Setting the Result var of the function is not necessary for a successful compile and only generates a compiler warning.

It turns out that I must specify any parameters as var. ie, this will work:
Code:
interface

type
  TDamage = type String;

function Concise([b]var[/b] AStr: String): String; overload;
function Concise([b]var[/b] AStr: TDamage): TDamage; overload;

but this won't
Code:
interface

type
  TDamage = type String;

function Concise(AStr: String): String; overload;
function Concise(AStr: TDamage): TDamage; overload;

This is a big pain, as it adds an extra variable and assignment to any call to functions or procedures like this as I will be calling these functions fairly often with code like this:
Code:
Entity.CauseDamage(Concise(TDamage(AItem.Damage + ',' + AExtraDamage)));
which I can't do if there's a var requirement. This is dangerous code, because if I accidently leave out the TDamage typecast then the wrong Concise will be called without giving me any warning. Maybe I should simply modify all of my functions and procedures to scan the string being passed to them to see if it contains a damage notation and then handle it accordingly.

One thing that does work is if I change the declaration of TDamage to 'TDamage = PChar'. But it doesn't remove the danger of the wrong functions being called.
 
Then why not just name them differently?
Like ConciseS and ConciseD for example?

Easy solution without dangers in my opinion.

[bobafett] BobbaFet [bobafett]
Code:
if not Programming = 'Severe Migraine' then
                       ShowMessage('Eureka!');
 
Hi BobbaFet,

I still think there would be danger with that approach, because ConciseS would still accept TDamage parameters, particular when I append TDamage parameters together, forcing them to be seen as a String. Solving the original issue (why doesn't this work?) has inadvertantly shown me that I shouldn't be going down that path at all.

You may remember to always use ConciseD when dealing with damage related variables or ConciseS when not, but I don't trust that I would. Concise is one example of a plethora of functions and procedures that would need to be duplicated to handle TDamage differently, and still many more wouldn't need to be duplicated, so I still think I'd be best off simply handling it all internally in those functions.

Your thoughts are very much appreciated though.
 
You've never really mentioned why you need an overloaded function, especially as they both just deal with a string. Why not just have one function? There is, after all, no point in using a feature of the language just purely for the fact that it's there.

I would consider
Code:
function Concise(AStr: String; IsDamage: Boolean): String;
to be much easier to read and use.
 
Hi KempCGDR,

My project has a lot of different objects with heaps of published properties that are referred to using RTTI. This is because the project is essentially an engine that runs using information from a database.

It made a sense initially to simply overload the necessary functions to handle TDamage specifiers properly.

As I indicated in my previous post, I started this topic primarily because I tried to do it this way and couldn't, and I wanted to know why. Through the discussion in this topic plus more playing around with my code, I've been convinced that overloading is not the way I should approach this, and instead use a combination if internal branching to handle strings that contain damage notation, plus differently named methods to specifically handle damage notation.
 
Well, here's a thought, how about typecasting TDamage as an
object with a string property. Then if you pass it to the
wrong one it just won't compile if you combine that with
ConciseS and ConciseD.

[bobafett] BobbaFet [bobafett]
Code:
if not Programming = 'Severe Migraine' then
                       ShowMessage('Eureka!');
 
Thanks BobbaFet - As I said in my original post, I want to stay away from having to Create and Destroy instances of TDamage, just because of the nature in which they will be used. For example, my TEntity and TItem objects will each of a Damage property that will need to be combined at times (with even more TDamage properties sometimes) and passed to things such as TListBoxes, or just other methods. It's impossible to know how long each TDamage will need to exist for, so it makes more sense to use standard variables.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top