Primitive types have default conversion rules, a lot of programming languages work this way by default. This is so that you don’t have to typecast everything and it’s really a convenience. For example, you’ll be able to assign an Integer to an Extended without trouble, both by passing a literal 42 as well as assigning a variable of type Integer.
procedure Hello; var SomeNumber: Extended; AnotherNumber: Integer; begin AnotherNumber := 6; SomeNumber := 2; // works SomeNumber := AnotherNumber; // works end;
Even if do type aliasing, the types are still the types they were and have automatic conversion rules:
type ANewType = Extended; AnotherNewType = Integer; implementation procedure Hello; var SomeNumber: ANewType; AnotherNumber: AnotherNewType; begin AnotherNumber := 6; SomeNumber := 2; // works SomeNumber := AnotherNumber; // works end;
If you really want strict conversion rules, because for example you want to avoid meters being assigned to seconds or vice versa, you will need to create new types. And new types are created by using either a record or a class.
To allow certain conversions, you can add those rules to the types using operator overloading. (see https://docwiki.embarcadero.com/RADStudio/Sydney/en/Operator_Overloading_(Delphi))
In FPC the syntax is different, but you can do the same https://www.freepascal.org/docs-html/ref/refse104.html#x224-24800015.3
You can then even make conversion rules for meters * seconds creating a meters per second type.
Here’s an example of how it works in Delphi:
type metersPerSecond = record private m: Extended; s: Extended; value: extended; mset: Boolean; sset: Boolean; function Units: string; public function ToString: string; end; meters = record private value: Extended; function Units: string; public class operator Implicit(Value: Extended): meters; class operator Explicit(Value: meters): metersPerSecond; class operator Multiply(ms: metersPerSecond; m: meters): metersPerSecond; function ToString: string; end; seconds = record private value: Extended; function Units: string; public class operator Implicit(Value: Extended): seconds; class operator Explicit(Value: seconds): metersPerSecond; class operator Multiply(ms: metersPerSecond; s: seconds): metersPerSecond; function ToString: string; end; implementation uses SysUtils; class operator meters.Implicit(Value: Extended): meters; begin Result.value := Value; end; class operator seconds.Implicit(Value: Extended): seconds; begin Result.value := Value; end; class operator meters.Explicit(Value: meters): metersPerSecond; begin Result.m := Value.value; Result.mset := True; if Result.sset then Result.value := Result.s * Result.m; end; class operator seconds.Explicit(Value: seconds): metersPerSecond; begin Result.s := Value.value; Result.sset := True; if Result.mset then Result.value := Result.s * Result.m; end; class operator seconds.Multiply(ms: metersPerSecond; s: seconds): metersPerSecond; begin Result := ms; Result.s := s.value; Result.sset := True; if Result.mset then Result.value := Result.s * Result.m; end; class operator meters.Multiply(ms: metersPerSecond; m: meters): metersPerSecond; begin Result := ms; Result.m := m.value; Result.mset := True; if Result.sset then Result.value := Result.s * Result.m; end; function metersPerSecond.Units: string; begin Result := 'm/s'; end; function metersPerSecond.ToString: string; begin Assert(mset and sset); Result := Format('%f%s', [value, Units]) end; function meters.Units: string; begin Result := 'm'; end; function meters.ToString: string; begin Result := Format('%f%s', [value, Units]); end; function seconds.Units: string; begin Result := 's'; end; function seconds.ToString: string; begin Result := Format('%f%s', [value, Units]); end; var time: seconds; distance: meters; speed: metersPerSecond; different_speed: metersPerSecond; initialization time := 10.0; distance := 3; // distance := meters; // does not work, because seconds are not meters! speed := metersPerSecond(time) * distance; // or the other way around speed := metersPerSecond(distance) * time; WriteLn('speed -> ' + time.ToString + ' * ' + distance.ToString + ' = ' + Speed.ToString); // different_speed := distance; // this doesn't work without explicit conversion WriteLn('different_speed -> ' + different_speed.ToString); end.
Contact
GDK Software UK
(+44) 20 3355 4470GDK Software USA
+1 (575) 733-5744