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

8 0 beta #10592

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

8 0 beta #10592

wants to merge 190 commits into from

Conversation

derrell
Copy link
Member

@derrell derrell commented May 13, 2023

New class/property system

Copy link
Contributor

@cboulanger cboulanger left a comment

Choose a reason for hiding this comment

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

Exciting! I hope I will have the opportunity to test it in the near future. Until then- as it passed the tests, I trust it's ready as it is for a breaking release

… a compatible release.

also, fixes an issue where the environment check `qx.future.checkjsdoc` is now declared as `qx.Class.futureCheckJsDoc` so that the compiler can detect it and eliminate code (this fixes the require warning for jsdoctypeparser)
also, blocks declaring variables called `arguments` which breaks uglify
@johnspackman
Copy link
Member

I'm finding this quite hard to debug - stepping into an ordinary method called getUserAsync() does not take me to the function - instead I have to step through https://github.com/qooxdoo/qooxdoo/blob/8_0_beta/source/class/qx/Class.js#L902-L921 in order to get to my code; while stepping through the code, the values in the debugger are not what I would expect (eg the value at https://github.com/qooxdoo/qooxdoo/blob/8_0_beta/source/class/qx/Class.js#L911 is my function and not the return of the function).

While debugging, the inspector shows nothing at first:
image

and when the [[Target]] is expanded there is a huge array of properties in the object:
image

There's another 4 pages of property values, and my actual properties are hidden in the middle.

Is it the case that every method call will be wrapped with a function? What effect does the extra properties in the object have on memory usage?

@derrell
Copy link
Member Author

derrell commented Jun 1, 2023

Yes, deep debugging requires a bit of getting used to, but once you get used to it, you learn to quickly run-until-function-exit on some of the calls. It's not that each is wrapped in a function; rather, the proxy wraps the entire object. Every access to the object runs through the proxy. That includes access to methods, so first, you'll see a get of the method itself, and then you'll see the method invocation. That fist get of the method is one that you learn to ignore and immediately step out of. As I worked with this system, I found it far, far easier to debug properties than the original generated code, once I got used to working with it and learned to quickly step past the non-property accesses.

@derrell
Copy link
Member Author

derrell commented Jun 1, 2023

BTW, the vast majority of those object properties already existed in the old property system, but you typically had no reason to notice them. I added a few as necessary features of the new property system.

@johnspackman
Copy link
Member

Yes, deep debugging requires a bit of getting used to, but once you get used to it, you learn to quickly run-until-function-exit on some of the calls

Every other debugging experience I can think of just steps into the function. It looks really odd, and I can't imagine new users taking to it very easily.

BTW, the vast majority of those object properties already existed in the old property system

I don't remember seeing them; they were presumably in the prototype or in a closure before? My debugger now shows 210 properties when there were approx 30 before.

IMHO that is confusing and makes it difficult to see whats going on.

@johnspackman
Copy link
Member

johnspackman commented Jun 1, 2023

also there seems to be a problem, maybe connected to the function being an async function - I cannot step into my function, the value variable is the function, not the result of the function:

image

this is in the handler:
image

this is the actual function definition:
image

Copy link
Member

@johnspackman johnspackman left a comment

Choose a reason for hiding this comment

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

This PR has quite an impact on debuggability - every single method call (not just properties) now goes via the proxy handler code; IMHO that's a bit confusing and distracting. Also, every property now causes 7 fields to be added to each object, which adds pages of irrelevant details to an object.

AIUI Object.defineProperty can be used to achieve the desired effect (ie native property values) without using Proxy, meaning that debugging is much simpler.

Here's a proof of concept that native properties can be added to the existing v7 qx.Class classes:

https://tinyurl.com/2gk2jpvy

Copy link
Member

@johnspackman johnspackman left a comment

Choose a reason for hiding this comment

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

Pseudo properties need to be supported also, eg qx.ui.form.List has a selection property but it only appears as getSelection and not as selection:

image

@derrell
Copy link
Member Author

derrell commented Jun 2, 2023

I don't know what a pseudo property is. Something is either defined in the properties configuration, or it is not. There are a few places that kind of simulate properties, but I'm not sure what you'd have the code do here. Guess that when there is a getX method, that means there should be an x property automatically added? That doesn't work if the getter method is actually retrieving the value from someplace else, e.g., some sub-object as is commonly done. I don't think I'm comfortable with guessing...

Add cross compiler to 8.x beta
@johnspackman
Copy link
Member

I don't know what a pseudo property is.

we discussed it here: #10410

There are a few places that kind of simulate properties

they do this because the property system did not allow custom storage

I don't think I'm comfortable with guessing...

It's what qooxdoo does and how binding works. It sniffs, basically deciding that if there is a get, set, reset, and change event, it is a property.

@derrell
Copy link
Member Author

derrell commented Jun 2, 2023

Ok, I've added support for pseudo-properties. I excluded the test for the reset method, as it seems it's not required: the example of MModelSelection's selected pseudo-property doesn't have it, so I'm assuming it's not a required component of pseudo-properties.

I also added tests for it, as there apparently weren't any previously.

// Next try to parse the check string as JSDoc
let bJSDocParsed = false;
try {
const { parse } = require("jsdoctypeparser");
Copy link
Member

Choose a reason for hiding this comment

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

I appreciate that this is currently switched off, but IMHO we should not plan on including require in browser based builds because it forces the user to use npm and have a package; years ago, one of the 1&1 team added grunt and it was very frustrating to have to create a package.json etc just to be able to compile.

Copy link
Member Author

Choose a reason for hiding this comment

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

Remember that require in a browser-based app includes the browserified code. There should be o need for the user to use npm and have a package; the compiler should be browserifying that code from qooxdoo's node_modules.

That said, I don't have any strong need for this feature. We could strip it out completely. We could, later, implement it with our own code to parse JSDoc comments. Or whatever. Let me know if you'd like for me to entirely remove that code.

Copy link
Member

Choose a reason for hiding this comment

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

I think that the jsdoc parser would be useful, but at the moment browserify does not work as you're propising (although I think it would be good if it did). I havn't specifically tested, but the compiler was complaining that it could not find the module

Copy link
Member Author

Choose a reason for hiding this comment

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

It's possible that the node_modules path of qooxdoo needs to be added to the compiler's search for required modules for it to work as desired. That's a separate issue that I can look into it, but it's separate from this PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think that the jsdoc parser would be useful, but at the moment browserify does not work as you're propising (although I think it would be good if it did). I havn't specifically tested, but the compiler was complaining that it could not find the module

I just pushed a fix to this. The compiler now looks in both the app's node_modules directory and qooxdoo's node_modules directory for browserifyable modules. This means that jsdoctypeparser, used by Class.js (when enabled by the environment variable, later), is found regardless of whether there is a node_modules directory in the user's app.

CHANGELOG.md Outdated Show resolved Hide resolved
```
instance[2] = 42;
value = instance[2];
delete instance[2];
Copy link
Member

Choose a reason for hiding this comment

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

please can you explain how delete is implemented? EG does this mean that you could have two objects of the same class, but one has undefined for the property because it has been deleted but the other does not, even if the definition of the property says that an uninitialised value is impossible?

Copy link
Member Author

Choose a reason for hiding this comment

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

Calling delete instance[2] is identical to calling instance.removeAt(2) because the delete is trapped and removeAt is actually called in its stead.

},

delete(property) {
// If the property is a number or string representing a number...
Copy link
Member

Choose a reason for hiding this comment

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

delete dataArray[2] is not the same as dataArray.removeAt(2) because delete will simply create a hole in the array where as removeAt will shuffle the elements down. Does qx.data.Array support sparse arrays?

Copy link
Member Author

Choose a reason for hiding this comment

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

delete dataArray[2] in qx.data.Array is implemented as dataArray.removeAt(2). I don't believe that qx.data.Array supports sparse arrays, so we probably don't want dataArray.removeAt(2) to leave an undefined hole. The implementation is trivially changeable, though. Do you have suggestions for a different implementation? (It's marked as experimental, so what we do now can be changed later.)

Copy link
Member

Choose a reason for hiding this comment

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

But it's different semantics - calling delete myNativeArray[2] is not the same as myDataArray.removeAt(2)

Copy link
Member Author

Choose a reason for hiding this comment

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

Understood. What would you have it do instead?

Copy link
Member

Choose a reason for hiding this comment

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

throw an exception?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok. It now throws an exception by default. If environment variable qx.data.Array.deleteAsRemoveAt is true then it acts as I had implemented it originally.

@johnspackman
Copy link
Member

@derrell would it be possible to progress this PR? I appreciate you're busy, but it would be good to see it come to a conclusion

@ChristianMayer
Copy link

There wasn't any action for nearly a year now. Is this still active?

@johnspackman
Copy link
Member

There wasn't any action for nearly a year now. Is this still active?

Yes - I have a version which seems to be complete but I need to merge the current master into it so that I can do the tests; I'm just stupidly busy at work at the moment, sorry for the delay - I'm really keen to get it out

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

Successfully merging this pull request may close these issues.

None yet

7 participants