Profile cover photo
Profile photo
Stefan Glienke
450 followers
450 followers
About
Communities and Collections
Posts

One of these rare moments when the compiler positively impresses me

See this short and incomplete nonsense code:

type
IFoo = interface
procedure Bar;
end;

TBoo = class
end;

TBooHelper = class helper for TBoo
procedure Bar;
end;

TBar = class(TInterfacedObject, IFoo)
private
fBoo: TBoo;
property Boo: TBoo read fBoo implements IFoo;
end;

The thing that impressed me here was the fact that the interface delegation clause supports class helpers - very nice!

In production code this enables me to use interface delegation to some object without the need to create some wrapper/adapter object.

Post has attachment
And here is why I think twice before spending time to report feature requests to QP

And even bugs/unexpected behavior are regularly being sweeped under the carpet reclassified as new feature.

46 out of those 84 resolved/closed have the resolution "wont fix" or "works as expected".

This is not intended to be a flame but just pointing out the lack of emphasis on new features (at least those being reported in QP)

FYI: +Marco Cantù +David Millington +Horácio Filho
Photo

Coworker and me were just thinking if this (or similar syntax) would be nice to have in Delphi:

car := TCar.Create
begin
Name := 'Chevrolet Corvette';
Color := TColors.Yellow;
end;

Edit: After pointing out this might lead to code defects because begin end can be used regardless this feature here is another proposal (similar to how Oxygene does it):

car := TCar.Create(
Name: 'Chevrolet Corvette',
Color: Colors.Yellow,
MaxSpeedKm: 300
);

With a ctor that has an argument:

car := TCar.Create('Chevrolet Corvette'; // <- semicolon
Color: Colors.Yellow;
MaxSpeedKm: 300
);


Suggestion by +Eric Grange - like the original one but reusing the with to make it safe against issues using begin:

car := TCar.Create
with
Name := 'Chevrolet Corvette';
Color := Colors.Yellow;
MaxSpeedKm := 300
end;

Ctor with parameter:

car := TCar.Create('Chevrolet Corvette')
with
Color := Colors.Yellow;
MaxSpeedKm := 300;
end;

Similar to how since C# 3.0 you can initialize objects (see http://csharp.net-tutorials.com/csharp-3.0/object-initializers/)

or Oxygene: https://docs.elementscompiler.com/Oxygene/Members/Constructors/ -> "Extended Constructor Calls"

This is only allowed on a constructor call - that is not a with equivalent

Edit:

Here are the rules:
1) only assignments (or similar syntax with a colon like in c# or an equals sign like for default values in delphi or global variable initialization) allowed
2) only publicly accessible properties of the created objects are allowed on the left side of the expression
3) right side of the expression can be any expression compatible to the left side but not a member of the created instance

Some while ago I started a plugin to easily add units to the uses clause just like you can do via quickfix in VisualStudio.

I never actually polished it but since I felt it might be useful to others as well here it is (still beta - supported Delphi versions currently are 10, 10.1 and 10.2).

Just run the setup and install into a directory where the IDE will also have write access to (should be %localappdata% by default).

When you first start the IDE with the plugin it will index $(BDS)\source which should reasonably fast and you won't even notice it. You can then add additional directories via Options -> Third Party -> UsesHelper (or F6 -> UsesHelper). Just add any additional directories that should be indexed (recursively, only *.pas). Indexing will happen in the background. In the end it will save an index.dat file which it will only access when it gets changed or you restart the IDE.

Via shortcut (Shift+Alt+F10 - fix for now, might be configurable later) while in the editor on some symbol you can show the suggestion list for units that contain that symbol and add it to interface or implementation uses. What does not work yet is moving from one to the other if it already exists in either.

Let me know if there any issues and enjoy!

Oh, the download link:
https://1drv.ms/u/s!ArjIoB43KhwDg3Ju1tkHlJniN2WS

It just occured to me that when I have such code:

type
TFooBar = class
s: string;
end;

procedure Main;
var
x, y: TFooBar;
begin
x := TFooBar.Create;
y := TFooBar.Create;

x.s := 'True';
y.s := 'True';

Assert(Pointer(x.s) = Pointer(y.s));
end;

begin
Main;
end.

The assertion will raise because whenever you assign a string literal to a string variable it checks if the string is a const (refcount = -1) and then calls _NewUnicodeString). I guess this has been discussed already somewhere else but I cannot find anything regarding my question:

I would guess that even if it is a const it could assign that reference to s and don't touch the refcount. This should work fine with the cow mechanics.

But as it is this would mean that if code runs through such const string assignments every time a new string gets allocated, no?
In my case I am using the const string 'True' for nullables in Spring to set the "HasValue" flag for them (otherwise the field is empty). However by using a const there it creates a new string every time. So if you have 10 nullable values you have 10 string instances with the content "True". The only solution I found so far was to make the const a variable (in this case it works because its private) and assign 'True' to it in the initialization section (or could also in the class ctor). That way there is only one string instance with content 'True' for the nullables around.

Any other solution I am missing?

Edit: I found this SO question:
https://stackoverflow.com/questions/12837129/string-const-why-different-implementation-for-local-and-result so I changed the original example to use objects and non global variables.

In my case I know that the module the literal is coming from will not be unloaded before anyone that is using it. That makes me think if we would need some kind of const string with start refcount = 1. Since its a const you could not modify it (which would modify the const because of refcount 1) but when assigning somewhere the same reference is being used and no new strings are being produced. I guess I am missing some cornercases why this is not possible -.- So I probably will use the hidden string variable to get the same result.

Post has attachment

Post has attachment

I have the following situation:

I have enumerator classes that have a MoveNext and some internal state. The first time MoveNext is called additionally to the usual logic of MoveNext it needs to do some initialization. Currently the code is basically like this:

function TEnumerator.MoveNext: Boolean;
begin
Result := False
if state = init then
begin
DoInit;
state := running;
end;
if state = running then
begin
// usual movenext stuff...
end;
end;

In languages with case/switch fallthrough I could simply write it like this:

case state of
init:
begin
DoInit;
state := running;
end;
running:
begin
// usual movenext stuff
end;
end;

I am seriously tempted to use a label and a goto here but I was wondering if anyone has another idea to avoid checking state twice.

It seems I found another piece to the puzzle of generics causing big binaries and slow compile times:

https://quality.embarcadero.com/browse/RSP-18080

It looks like the compiler puts more into a dcu than it should/have to. That causes some cascading effect if you have a project with many units that all suffer from this.

In my case I have a project with roughly 53k loc that compiles for 22sec and causes the IDE to go from 300MB to a little over 1GB RAM usage. But not only that it also causes the IDE to become sluggish right after that (yeah yeah, I can use msbuild to not let the IDE suffer but that's not the point). It goes away when I close the project but working with it and compiling even more projects makes it worse. The project is producing 73MB of dcu files that mostly contain the same stuff over and over (most of it being generic collection classes that are not even used but being pulled in because of the bug reported). Some of them being some couple hundred lines of trivial classes doing some list stuff becoming >2MB dcu files.

Sure, once the binary gets linked duplicates are being removed (not completely folded but if 2 units used a TList<TFoo> there is only one remaining) but I feel most of the performance here is being wasted for emitting useless code into the dcus (and compiler memory) that later is being thrown away again and is also causing stress for the linker (you can typically see that generic heavy projects hang on the linking phase way longer than "classic" code).

P.S. Yes, this is using Spring4D collections and I am working on some fix to mitigate this problem a bit but there is only so much I can do :(

Does anyone remember if Delphi XE somewhere had the option to turn off generating a dcu for a dpk?

I have the case where my package contains a unit with the same name which works fine in recent Delphi versions but not on XE because the dcu of the unit is overridden when the compiler emits the dcu for the package.

Comments suggesting to name them differently will implode when being posted! ;)
Wait while more posts are being loaded