Rollo62 563 Posted Thursday at 10:13 AM Hi there, I'm trying a bit with with custom records and have here some minimal example. Its about the API to work with such records. I wonder what will be the right way, to use it in the following scenario, without warnings: unit UMyCustomRecordDemo; interface type TMyCustomRecord = record public type TMyEnum = ( meFalse, meTrue ); private FValue: TMyEnum; public // Standard-Operators for Custom Managed Records class operator Initialize(out Dest: TMyCustomRecord); class operator Finalize(var Dest: TMyCustomRecord); class operator Assign(var Dest: TMyCustomRecord; const [ref] Src: TMyCustomRecord); // Factory-Method, which shall prepare a new record, that can be used with inline variables and intrinsic type evaluation class function Make_Record: TMyCustomRecord; static; end; implementation class operator TMyCustomRecord.Initialize(out Dest: TMyCustomRecord); begin Dest.FValue := meFalse; end; class operator TMyCustomRecord.Finalize(var Dest: TMyCustomRecord); begin // Finalize if necessary end; class operator TMyCustomRecord.Assign( var Dest : TMyCustomRecord; const [ref] Src : TMyCustomRecord ); begin // Simple copy of internal values Dest.FValue := Src.FValue; end; class function TMyCustomRecord.Make_Record : TMyCustomRecord; begin // This shall prepare a new record Result.FValue := meFalse; end; end. And it would be used like that procedure TestMyCustomRecord; var LRec1: TMyCustomRecord; begin // This assignment throws the warning: W1048 Unsafe typecast of '%s' to '%s' (Delphi) //Yes, it may be caused by temporary object and assignment, which is not most performant. LRec1 := TMyCustomRecord.Make_Record; //I would like to use this, as elegant way to make and prepare a new variable var LRec2 := TMyCustomRecord.Make_Record; end; My question is, are CustomManagedRecords not intended to be used in Function results, because there is no nice easy way to get rid of these warnings? How about functions returning Records in general, this is not the most efficient way, I know, the pro's are its readability. Would there be an elegant way out of this problem (maybe by records using classes or smartpointers internally, but would such overhead be worth it for simple records? And yes, I know that a "getter" would solve it, but not as elegant as above API: TMyCustomRecord.Make_Record( LRec ); Share this post Link to post
Rollo62 563 Posted Friday at 07:18 AM What I have found is that aside the usual [unsafe] there is a specific [Result: unsafe] attribute, which can be used before member functions, where I have assumed that this might suppress the warnings. https://docwiki.embarcadero.com/Libraries/Seattle/en/System.UnsafeAttributehttps://docwiki.embarcadero.com/Libraries/Seattle/en/System.UnsafeAttribute This should be applicable to functions as well, but it doesn't suppress these unsafe typecase warnings But it also says: Quote Warning: UnsafeAttribute should be only used outside the System unit. It is considered dangerous and its use is not recommended. There is also the unsafe method modifier, or maybe unsafe keyword how Marco called it, which can be added behind a function. This does more than just compiler magic, but it seems to modify reference counting. So this is not what I'm looking for, but mybe with Recors it does this job? Is the [Result: unsafe] attribute maybe a leftover from the mobile ARC stuff and nowadays has no meaning? I'm unsure what this really should do, except suppress warnings. There was an old whiteparer "The Delphi Language for Mobile Development" from 2013, which seems not available any more. What I'm looking for is a selective way to suppress the warnings a Record level, to tell the compiler that I take the responsibility. Share this post Link to post
Der schöne Günther 334 Posted Friday at 08:23 AM I don't get a warning for the above code at all 🤷♂️ Share this post Link to post
Rollo62 563 Posted Friday at 01:08 PM 4 hours ago, Der schöne Günther said: I don't get a warning for the above code at all 🤷♂️ Perhaps you don't have activated them in the project I try from time to time to cleanup all warnings, but with these "unsafe" checked I've got a huge list with myriads of warnings. Thats why I try to find a better design, how to remove them. Since I usually see warnings same as errors, I try to remove them all, but with these settings nearly every unit ( System units too ) produce massive warnings. All in all they were maybe not so critical, or came from a different ARC-era, but still they point towards some possible flaws in code. I think its always worth to try to find better solutions. Share this post Link to post
Uwe Raabe 2129 Posted Friday at 02:44 PM On 3/27/2025 at 11:13 AM, Rollo62 said: there is no nice easy way to get rid of these warnings IMHO, this warning is just bogus and it shouldn't be emitted in the first place. So the usual way would be to file a bug report to fix the compiler. Unfortunately there already exist a couple of issues about this warning and Embarcadero seems to prefer to ignore them because this warning is off by default and they see no sense in activating them. (Not that I would actually support this solution.) In case you need to keep these warnings active, you might consider wrapping all occurrences in {$WARN UNSAFE_CAST OFF} ... {$WARN UNSAFE_CAST DEFAULT} Share this post Link to post
Rollo62 563 Posted Friday at 04:45 PM 1 hour ago, Uwe Raabe said: IMHO, this warning is just bogus and it shouldn't be emitted in the first place. Thanks, but I think this can still have a true core. From my understanding, this warning tells us, that there is a temporary object, which will be automatically assigned by the custom assignment operator, where the compiler cannot really check the assignment, because its "custom". So in my opinion this warning maybe has some good reasons behind and could be helpful. It would be great if I could take control with the [Result: unsafe] attribute, by telling the compiler: "Nevermind, I know how to handle this case, just keep silent about it." Since I only look into this from time to time, I keep it like that, but maybe for some hard debug sessions this might be useful to switch it on and find some good hints to look into. I'm still in a 50:50 position here. Share this post Link to post
Uwe Raabe 2129 Posted Friday at 05:02 PM 12 minutes ago, Rollo62 said: From my understanding, this warning tells us, that there is a temporary object, which will be automatically assigned by the custom assignment operator, where the compiler cannot really check the assignment, because its "custom". IMHO, it absolutely makes no sense to issue a warning about an Unsafe typecast of <mytype to <mytype>, when neither these are different types nor any type cast is done at all (let alone one being unsafe). The most matching issue in QP is probably this one: https://quality.embarcadero.com/browse/RSP-30869. Given that it seems to be fixed, there may be a good chance that the current failure will be fixed, too. Share this post Link to post
Rollo62 563 Posted Saturday at 08:15 AM 14 hours ago, Uwe Raabe said: ... when neither these are different types nor any type cast is done at all (let alone one being unsafe). I would agree, if we talk about 100% compiler managed code. BTW: This warning really only appears with custom CMR, if I replace this by a "normal" Delphi Record, then there is no warning, which I would expect too. Now I can use this warning to find places where custom CMR might cause issues, which would become handy to debug sporadic, unclear issues maybe, where you got no idea where to look at. So I like the warnings and don't think all of them were bogus, at least for the CRM records. Imagine you have an only half-implemented CMR record assignment operator, then you might be pointed to this issue a bit. This could be a perfectly fine, accepted behaviour by design, but good to see these warnings as reminders. Yes, I could make a hint about such special-design decisions in the record itself, but then I wouldn't backtrack the places where it is used so easily. Nevermind, if there is nothing wrong with the code, I will keep it like that. I was looking for a perhaps better implementation, like SmartPointer, Getter, or the like ... returning plain Records as result is maybe never the best idea, only for readability. But the overhead of those other solutions over a simple Record doesn't make it better, IMHO ( and yes, I'm not looking for highest-performance design here, just normal code ). Share this post Link to post