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

v2 Pos classes need to support interrogation for TGD #3482

Closed
tznind opened this issue May 14, 2024 · 14 comments
Closed

v2 Pos classes need to support interrogation for TGD #3482

tznind opened this issue May 14, 2024 · 14 comments
Assignees
Labels
bug design Issues regarding Terminal.Gui design (bugs, guidelines, debates, etc...)
Milestone

Comments

@tznind
Copy link
Collaborator

tznind commented May 14, 2024

Executive Summary
It is no longer possible to know important things about a given Pos because of the use of primary constructors, whose parameters are innaccessible through reflection.

Detail
Consider Pos.PosView (aka relative to)

V1
In v1 fields were side and View

  • These were accessed via reflection in TGD

For example

    public static bool IsCombine( [NotNullWhen( true )] Pos? p )
    {
        if ( p == null )
        {
            return false;
        }

        return p.GetType( ).Name == "PosCombine";
    }

Also

  var fTarget = posView.GetType().GetField("Target") ?? throw new Exception("PosView was missing expected field 'Target'");
  View view = (View?)fTarget.GetValue(posView) ?? throw new Exception("PosView had a null 'Target' view");

V2
In v2 internals are now visible to TGD (yay!) so can do like

if(p is Pos.PosCombine pc)
{
...
}

However there are some changes to use primary constructors e.g.

internal class PosView (View view, Side side) : Pos

v2 code for PosView

Since Side is no longer a field, we cannot read it in TGD. If in the debugger we examine the source for the object we get that it has this secret hidden field thats super sketchy.

        [CompilerGenerated]
        private Side _003Cside_003EP;

        public readonly View Target;

        public PosView(View view, Side side)
        {
            _003Cside_003EP = side;
            Target = view;
            base._002Ector();
        }

Fix
Fix will be to expose as public readonly the constructor properties e.g. like Side

This will enable the TGD to read them and support its UIs for designing/editting the position stuff is at.

    internal class PosView (View view, Side side) : Pos
    {
         public readonly View Target = view;
+        public Side TargetSide => side;
@tznind
Copy link
Collaborator Author

tznind commented May 14, 2024

Given that these classes are internal, is there any issue with making all the private fields public?

Also for those that are currently private e.g. _factor for PosFactor?

If public is acceptable then what is the best way to do that

  • public readonly field (Note that doing this for side somehow causes CS9124 )
  • public property (e.g. as above)
  • other?

If they are to stay private then I can still proceede with the existing reflection but will need private fields for the Pos/Dim that have primary constructors parameters)

@dodexahedron
Copy link
Collaborator

dodexahedron commented May 14, 2024

Something you may want to check out that avoids manual reflection and is super speedy for member access:

UnsafeAccessorAttribute

That thing can basically be thought of as a reverse InternalsVisibleTo sort of thing that also works for private, and is declared in the consumer's code (InternalsVisibleFrom? 😅).

If we had some interfaces for things, the combination of that attribute and interfaces could make your life soooo much easier.

As for addressing the problem, though:

Why is direct access to the fields necessary? Wouldn't you want to always be going through the property accessors, so that you're not coupled to implementation details?

@tznind
Copy link
Collaborator Author

tznind commented May 14, 2024 via email

@dodexahedron
Copy link
Collaborator

dodexahedron commented May 14, 2024

Gotcha.

I happened to update my previous reply like... Seconds after you replied just now, with a little bit more info, btw.

I think that attribute and TG getting interfaces that it should have anyway is probably the best solution overall, for TG and for TGD or anyone else wanting to get fancy with usage beyond the API itself. :)

@tznind
Copy link
Collaborator Author

tznind commented May 14, 2024 via email

@dodexahedron
Copy link
Collaborator

dodexahedron commented May 14, 2024

And as for the basic issue of how to figure it out...

The nested types are unfortunate.

Really should be an inheritance hierarchy.

There's no benefit at all to the nested types and any perceived benefit is a smell/kludge with far more idiomatic C# solutions available.

In fact, I think that was one of the first things I ever griped about when I initially started helping out with unit tests for TGD, before shifting focus to helping out over here with V2 first. 🤔

@tig
Copy link
Collaborator

tig commented May 14, 2024

The right thing to do here is consider Designer as a perfectly valid app and expose things it needs via a suitably designed public API.

I'm knee deep in DimPos.cs right now and have been fighting with myself over this very topic for different reasons.

I wasn't going to tackle solving this before I saw this Issue. Now I am. Stay tuned.

@tig
Copy link
Collaborator

tig commented May 14, 2024

This is the PR that will address this:

@dodexahedron
Copy link
Collaborator

As far as TGD goes, providing proper interfaces would allow @tznind to access a lot more than he currently can, without reflection or [UnsafeAccessor], which would be even better for him and for consumers of TG, TGD, and TG apps designed in TGD.

@dodexahedron
Copy link
Collaborator

Shifting gears to a completely different question for you @tznind:

Are you watching the stuff in .net 9.0 around dynamic persistent assembly creation? 😱 That stuff looks awesome.

@dodexahedron
Copy link
Collaborator

BAH.

Ok ignore literally all of that, because I was totally mis-reading the diffs.

My bad.

I'm pulling it down to look at it in-situ, now, instead of trying to make sense of the diffs.

If you totally already took care of that in this PR you are my hero. ❤️

@dodexahedron
Copy link
Collaborator

Well.. Except for the dynamic persisted assemblies, for you, @tznind

That looks like a perfect thing for you, down the road.

@dodexahedron
Copy link
Collaborator

dodexahedron commented May 15, 2024

It's like Christmas in May!

I less than three you, @tig , for biting the bullet and doing this. :)

It's a big and difficult to review PR, so I'm going to compare locally in better tools than the github web UI once you're finished with it.

I do see some things we can and maybe should do, but they shouldn't be part of this one. It should probably be as isolated to the refactor of the type hierarchy as reasonably possible.

I'mma just delete the earlier comments rather than hiding them, since they were totally irrelevant and stoopid.

@dodexahedron
Copy link
Collaborator

But, related to one bit I mentioned: We should definitely look at removing any InternalsVisibleTo dependencies between TG and TGD that remain, as well, in support of the goal.

@tig tig self-assigned this May 20, 2024
@tig tig added bug design Issues regarding Terminal.Gui design (bugs, guidelines, debates, etc...) labels May 20, 2024
tig added a commit that referenced this issue May 23, 2024
Fixes #3469, #3473, #3482  - `Dim.Auto` fixes and `Pos`/`Dim` refactor to support TGD
@tig tig closed this as completed May 23, 2024
@tig tig added this to the V2 Alpha milestone May 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug design Issues regarding Terminal.Gui design (bugs, guidelines, debates, etc...)
Projects
No open projects
Status: ✅ Done
Development

No branches or pull requests

3 participants