New directive: {$incfile <varname> '<path>'}A directive, not a modeswitch - always available, regardless of
{$mode}.
Docs: docs/incfile.mdEmbed a file's bytes into your program at compile time as a
String constant. The file is read as raw bytes and baked into the binary right where the directive sits - no runtime file I/O, no external file dependency at run time.
program project1;
{$mode objfpc}{$H+}
{$incfile mysource 'project1.lpr'} // embed this very file at compile time
begin
writeln('I am ', Length(mysource), ' bytes of source:');
writeln(mysource); // ...and print it right back out
readln;
end.
mysource is a
String const holding the file's bytes byte-for-byte. Text or binary alike - the real use is baking assets into a single-file executable:
{$incfile icon 'assets/app.ico'} // binary, byte-exact
Path resolution matches
{$I}: an absolute path is used verbatim, a relative one is searched in the source-file directory, then the local and global include paths.
Notes- It expands to a const declaration, so it must sit where a const is valid: unit/program scope (after uses), or any local const position.
- The bytes are fixed at compile time - repointing the path needs a recompile. Large files inflate compile time, so keep it to reasonably-sized assets.
New intrinsic: Type()On by default in
{$mode unleashed}. No separate modeswitch.
Docs: docs/type-intrinsic.mdType(expr) yields the static type of an expression at compile time - Pascal's answer to C++
decltype and D
typeof. The operand is never evaluated (like
SizeOf): no code runs, no memory is read, no side effects fire, no range checks. It's valid anywhere a type is expected - declarations, typecasts, type-taking intrinsics (
Default,
SizeOf,
High,
Low, ...), generic arguments, and derived types (
array of,
^,
set of).
{$mode unleashed}
var
x: Double;
y: Type(x); // y is Double
b: Byte;
begin
b := 7;
y := Type(x)(b); // typecast - cast b to whatever type x has
writeln('b = ', b, ', y = ', y:0:4); // b = 7, y = 7.0000
readln;
end.
Because the operand isn't evaluated, you can name the type of storage that doesn't exist at runtime - an element of an empty array, a null dereference, a not-yet-allocated field:
{$mode unleashed}
var
a: array of Integer; // empty; A[0] would range-check at runtime
begin
writeln(High(Type(a[0]))); // 2147483647 - element type only, a[0] never read
readln;
end.
It composes with type inference, so one inference site can drive several declarations without ever spelling the type out:
{$mode unleashed}
uses Classes;
function MakePoint(x, y: Integer): TPoint;
begin
result.X := x;
result.Y := y;
end;
begin
var z := MakePoint(3, 4); // z inferred as TPoint
var a: array of Type(z); // array of TPoint
var n: Type(z); // TPoint
// change MakePoint's result type and all of these follow
end.
Notes- The operand must still type-check - only its evaluation is skipped. An undeclared identifier or illegal expression is still an error.
- On a constant expression you get the smallest type that fits: Type(1+2) is a byte-sized subrange (SizeOf = 1), not Integer. Anchor it with a cast or a typed variable - Type(Integer(5)).
- Why not typeof: that name already means an RTTI/VMT operator in Object Pascal, and type is a keyword. The ( disambiguates Type( from the type keyword; other modes reject it exactly as before, so existing code is unaffected.