Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solution for Issue #125 and reverted change made in commit e90fee5 related to {$M-} #126

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

alydouglas
Copy link

Added fix for comparing records using a custom comparer that can be registered for use with the TValueHelper.CompareValue routine. Although I added this with the intention of using it for records, I have added it at a higher level on the assumption that other types (or use cases) could benefit from custom comparisons. I'm thinking this could be good for objects when comparing the contents may be preferable?

I have also reverted a change made in e90fee5 where the logic {$M-} for IWeakReferenceableObject was removed. This change unfortunately borked the use of {$M+} at the project level for me. This has had no adverse effects on my use case but this change was made for a reason.

…mpareValue for tkRecord

Added ability to register custom comparison routines which cann be used for all types but primarily designed to be used with records
Copy link
Member

@vincentparrett vincentparrett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fantastic otherwise. I was also planning on looking at record comparisons using RTTI, to see if the records had operator overloads that could be used for comparison when time permits.


type
//Allow custom comparisons
TCustomValueComparer = reference to function(const a, b: TValue): Integer;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea if it's possible, but did you try doing something like
TCustomValueComparer = reference to function<T>(const a, b: T): Integer;
that would allow us to avoid TValue

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that would be possible as I think you might need to declare it as TCustomValueComparer<T> = reference to function<T>(const a, b: T): Integer; so it couldn't be stored in a common container. Having said that, I am sure there should be a way to do this without the need for TValue?

TCustomValueComparer = reference to function(const a, b: TValue): Integer;
TCustomValueComparerStore = record
private
class var CustomComparers: TDictionary<Pointer, TCustomValueComparer>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this not be
class var CustomComparers: TDictionary<PTypeInfo, TCustomValueComparer>;
ie more strongly typed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good point, will update that.

@vincentparrett
Copy link
Member

Nice work.

@alydouglas
Copy link
Author

Thanks and thank you for providing Delphi Mocks on GitHub; I've been really enjoying jumping in to testing using it with DUnitX.

@alydouglas
Copy link
Author

Let me know what you think about the above changes to the comparer behaviour. This seems like a good way to allow the user to see TCustomValueComparer<T>, and internally be able to store and use the TCustomValueComparer with the data represented by TValue.

@vincentparrett
Copy link
Member

Changes look good. Can I ask one more thing before I merge this, add a few unit tests that at least exercise this functionality.

@alydouglas
Copy link
Author

Sure, I’ll try get that done this week and push the changes when ready.

@vincentparrett
Copy link
Member

BTW, the way you solved getting rid of TValue was ingenious, I would never have thought to use untyped parameters.. tbh I don't think I have ever used them intentionally before :)

@alydouglas
Copy link
Author

Thanks for the praise but I was not overly comfortable with the untyped parameters. I tend to avoid them as it doesn't really fit in well with the general Delphi philosophy of being as strongly typed as possible.

So as you will see from the new changes, I have updated the behaviour to rely entirely on generics. It is much better than the untyped parameters as I found that depending on the underlying type in TValue, you cannot always use the raw data like I had.

Will get those tests done this week and hopefully this provides some useful functionality to others!

@vincentparrett
Copy link
Member

This PR is looking good, however I suspect it might fail with 10.4 Managed records, as they have a specific Kind tkManagedRecord? Did you look managed records?

@vincentparrett
Copy link
Member

@alydouglas did you ever look at this with 10.4 and managed records? If you can that would be great. Also you will need to rebase this off master again due to other changes since this PR.

@alydouglas
Copy link
Author

@vincentparrett sorry that I let this slip last year, unfortunately job priorities shifted and I didn't have the time to spend on it. We are now moving across to 10.4 so I will give this another look and see how managed records affects things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants