Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@AndrewJakubowicz
Copy link
Contributor

Fixes: #4486

For context see the issue. It is now possible to pass an abstract class to the mixin and have it type check.

Test plan

Added type and runtime unit tests to ensure that both concrete and abstract classes are watched correctly.

@changeset-bot
Copy link

changeset-bot bot commented Jan 10, 2024

🦋 Changeset detected

Latest commit: 6435447

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@lit-labs/preact-signals Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Jan 10, 2024

📊 Tachometer Benchmark Results

Summary

nop-update

  • this-change, tip-of-tree, previous-release: unsure 🔍 -3% - +5% (-0.39ms - +0.61ms)
    this-change vs tip-of-tree

render

  • this-change: 47.63ms - 50.04ms
  • this-change, tip-of-tree, previous-release: unsure 🔍 -2% - +7% (-0.34ms - +1.25ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: unsure 🔍 -2% - +3% (-0.55ms - +1.08ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: faster ✔ 0% - 3% (0.13ms - 1.17ms)
    this-change vs tip-of-tree

update

  • this-change: 498.20ms - 508.80ms
  • this-change, tip-of-tree, previous-release: unsure 🔍 -4% - +9% (-1.66ms - +3.39ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: unsure 🔍 -0% - +3% (-0.30ms - +1.74ms)
    this-change vs tip-of-tree
  • this-change, tip-of-tree, previous-release: unsure 🔍 -1% - +0% (-5.30ms - +2.21ms)
    this-change vs tip-of-tree

update-reflect

  • this-change: 503.80ms - 517.16ms
  • this-change, tip-of-tree, previous-release: unsure 🔍 -1% - +0% (-4.72ms - +1.37ms)
    this-change vs tip-of-tree

Results

this-change

render

VersionAvg timevs
47.63ms - 50.04ms-

update

VersionAvg timevs
498.20ms - 508.80ms-

update-reflect

VersionAvg timevs
503.80ms - 517.16ms-
this-change, tip-of-tree, previous-release

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
18.42ms - 19.76ms-unsure 🔍
-2% - +7%
-0.34ms - +1.25ms
unsure 🔍
-2% - +6%
-0.45ms - +1.17ms
tip-of-tree
tip-of-tree
18.20ms - 19.07msunsure 🔍
-6% - +2%
-1.25ms - +0.34ms
-unsure 🔍
-4% - +3%
-0.73ms - +0.53ms
previous-release
previous-release
18.27ms - 19.19msunsure 🔍
-6% - +2%
-1.17ms - +0.45ms
unsure 🔍
-3% - +4%
-0.53ms - +0.73ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
38.77ms - 42.61ms-unsure 🔍
-4% - +9%
-1.66ms - +3.39ms
unsure 🔍
-2% - +12%
-0.72ms - +4.43ms
tip-of-tree
tip-of-tree
38.18ms - 41.47msunsure 🔍
-8% - +4%
-3.39ms - +1.66ms
-unsure 🔍
-4% - +9%
-1.39ms - +3.37ms
previous-release
previous-release
37.12ms - 40.56msunsure 🔍
-11% - +2%
-4.43ms - +0.72ms
unsure 🔍
-8% - +3%
-3.37ms - +1.39ms
-

nop-update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
11.13ms - 11.82ms-unsure 🔍
-3% - +5%
-0.39ms - +0.61ms
unsure 🔍
-3% - +6%
-0.32ms - +0.66ms
tip-of-tree
tip-of-tree
11.00ms - 11.73msunsure 🔍
-5% - +3%
-0.61ms - +0.39ms
-unsure 🔍
-4% - +5%
-0.44ms - +0.56ms
previous-release
previous-release
10.96ms - 11.65msunsure 🔍
-6% - +3%
-0.66ms - +0.32ms
unsure 🔍
-5% - +4%
-0.56ms - +0.44ms
-
this-change, tip-of-tree, previous-release

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
33.26ms - 34.59ms-unsure 🔍
-2% - +3%
-0.55ms - +1.08ms
unsure 🔍
-1% - +4%
-0.23ms - +1.34ms
tip-of-tree
tip-of-tree
33.18ms - 34.13msunsure 🔍
-3% - +2%
-1.08ms - +0.55ms
-unsure 🔍
-1% - +3%
-0.35ms - +0.93ms
previous-release
previous-release
32.94ms - 33.79msunsure 🔍
-4% - +1%
-1.34ms - +0.23ms
unsure 🔍
-3% - +1%
-0.93ms - +0.35ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
67.82ms - 69.64ms-unsure 🔍
-0% - +3%
-0.30ms - +1.74ms
unsure 🔍
-1% - +2%
-0.75ms - +1.54ms
tip-of-tree
tip-of-tree
67.54ms - 68.47msunsure 🔍
-3% - +0%
-1.74ms - +0.30ms
-unsure 🔍
-2% - +1%
-1.16ms - +0.51ms
previous-release
previous-release
67.64ms - 69.03msunsure 🔍
-2% - +1%
-1.54ms - +0.75ms
unsure 🔍
-1% - +2%
-0.51ms - +1.16ms
-
this-change, tip-of-tree, previous-release

render

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
32.72ms - 33.32ms-faster ✔
0% - 3%
0.13ms - 1.17ms
faster ✔
0% - 4%
0.11ms - 1.21ms
tip-of-tree
tip-of-tree
33.25ms - 34.10msslower ❌
0% - 4%
0.13ms - 1.17ms
-unsure 🔍
-2% - +2%
-0.63ms - +0.61ms
previous-release
previous-release
33.23ms - 34.14msslower ❌
0% - 4%
0.11ms - 1.21ms
unsure 🔍
-2% - +2%
-0.61ms - +0.63ms
-

update

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
503.00ms - 508.22ms-unsure 🔍
-1% - +0%
-5.30ms - +2.21ms
unsure 🔍
-1% - +0%
-4.66ms - +2.38ms
tip-of-tree
tip-of-tree
504.46ms - 509.86msunsure 🔍
-0% - +1%
-2.21ms - +5.30ms
-unsure 🔍
-1% - +1%
-3.17ms - +4.00ms
previous-release
previous-release
504.39ms - 509.11msunsure 🔍
-0% - +1%
-2.38ms - +4.66ms
unsure 🔍
-1% - +1%
-4.00ms - +3.17ms
-

update-reflect

VersionAvg timevs this-change
vs tip-of-tree
tip-of-tree
vs previous-release
previous-release
this-change
511.18ms - 514.58ms-unsure 🔍
-1% - +0%
-4.72ms - +1.37ms
unsure 🔍
-0% - +1%
-1.78ms - +3.34ms
tip-of-tree
tip-of-tree
512.03ms - 517.08msunsure 🔍
-0% - +1%
-1.37ms - +4.72ms
-unsure 🔍
-0% - +1%
-0.72ms - +5.62ms
previous-release
previous-release
510.19ms - 514.02msunsure 🔍
-1% - +0%
-3.34ms - +1.78ms
unsure 🔍
-1% - +0%
-5.62ms - +0.72ms
-

tachometer-reporter-action v2 for Benchmarks

@github-actions
Copy link
Contributor

The size of lit-html.js and lit-core.min.js are as expected.

Base: T
): T {
return class SignalWatcher extends Base {
abstract class SignalWatcher extends Base {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hm, should SignalWatcher itself be abstract? I guess probably so.

However technically you could do:

class MyElement extends LitElement {...}

customElements.define('my-element', SignalWatcher(MyElement));

Copy link
Member

Choose a reason for hiding this comment

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

The test below "class returned from signal-watcher should be directly instantiable if non-abstract" seems to suggest this is possible as is.

The tests show an interesting behavior. While I would've expected returning an abstract class here would always result in an abstract class that's non-instantiable, it seems it's still instantiable if the class provided to the mixin is non-abstract?

So then the reason for the addition of abstract in this line is to preserve the abstract behavior if the class provided to the mixin is also abstract. I don't know if that's something we strictly need to preserve, but seems unlikely to be a problem.

Copy link
Contributor Author

@AndrewJakubowicz AndrewJakubowicz Jan 10, 2024

Choose a reason for hiding this comment

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

customElements.define('my-element', SignalWatcher(MyElement)); is possible and tested by this PR here.

The tests show an interesting behavior. While I would've expected returning an abstract class here would always result in an abstract class that's non-instantiable, it seems it's still instantiable if the class provided to the mixin is non-abstract?

This is accurate. If the passed in class is non-abstract, then the resulting class from the mixin is non-abstract. This is due to the type signature of the mixin, which takes in Base: T, and returns T. So the return type matches the exact class passed in. The mixing-in of SignalWatcher is not reflected in the type system.

So then the reason for the addition of abstract in this line is to preserve the abstract behavior if the class provided to the mixin is also abstract.

This is required in order to pass in an abstract class with abstract members. Otherwise, within the mixin we'd get a type error suggesting that abstract methods/fields need to be implemented. By marking the mixin class abstract, the abstract methods do not need to be implemented by the mixin. We get to have our cake and eat it too, because the abstract mixin class is not reflected in the return type as mentioned above. So a concrete class being passed in can still be directly newed.

Copy link
Member

Choose a reason for hiding this comment

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

Thank you for the excellent explanation!

Base: T
): T {
return class SignalWatcher extends Base {
abstract class SignalWatcher extends Base {
Copy link
Member

Choose a reason for hiding this comment

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

The test below "class returned from signal-watcher should be directly instantiable if non-abstract" seems to suggest this is possible as is.

The tests show an interesting behavior. While I would've expected returning an abstract class here would always result in an abstract class that's non-instantiable, it seems it's still instantiable if the class provided to the mixin is non-abstract?

So then the reason for the addition of abstract in this line is to preserve the abstract behavior if the class provided to the mixin is also abstract. I don't know if that's something we strictly need to preserve, but seems unlikely to be a problem.

Copy link
Member

@augustjk augustjk left a comment

Choose a reason for hiding this comment

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

🎉

@AndrewJakubowicz AndrewJakubowicz merged commit b637103 into main Jan 11, 2024
@AndrewJakubowicz AndrewJakubowicz deleted the signal-watcher-abstract-support branch January 11, 2024 00:09
@lit-robot lit-robot mentioned this pull request Jan 31, 2024
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.

Preact-Signals SignalWatcher mixin does not support classes that inherit from abstract classes.

3 participants