Bug 191811 - Make lossy LayoutUnit constructors explicit
Summary: Make lossy LayoutUnit constructors explicit
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Ross Kirsling
URL:
Keywords: InRadar
Depends on:
Blocks: 191538
  Show dependency treegraph
 
Reported: 2018-11-17 14:11 PST by Ross Kirsling
Modified: 2019-05-20 18:37 PDT (History)
9 users (show)

See Also:


Attachments
Patch (7.17 KB, patch)
2018-11-17 14:14 PST, Ross Kirsling
no flags Details | Formatted Diff | Diff
Patch (26.89 KB, patch)
2018-11-17 17:43 PST, Ross Kirsling
ews-watchlist: commit-queue-
Details | Formatted Diff | Diff
Archive of layout-test-results from ews101 for mac-sierra (341.44 KB, application/zip)
2018-11-17 18:35 PST, EWS Watchlist
no flags Details
Archive of layout-test-results from ews106 for mac-sierra-wk2 (350.52 KB, application/zip)
2018-11-17 18:44 PST, EWS Watchlist
no flags Details
Archive of layout-test-results from ews116 for mac-sierra (315.80 KB, application/zip)
2018-11-17 18:49 PST, EWS Watchlist
no flags Details
Archive of layout-test-results from ews200 for win-future (1.37 MB, application/zip)
2018-11-17 19:09 PST, EWS Watchlist
no flags Details
Patch (33.45 KB, patch)
2018-11-19 23:57 PST, Ross Kirsling
ews-watchlist: commit-queue-
Details | Formatted Diff | Diff
Archive of layout-test-results from ews102 for mac-sierra (428.07 KB, application/zip)
2018-11-20 00:50 PST, EWS Watchlist
no flags Details
Archive of layout-test-results from ews106 for mac-sierra-wk2 (479.30 KB, application/zip)
2018-11-20 00:56 PST, EWS Watchlist
no flags Details
Patch (190.65 KB, patch)
2018-11-21 16:43 PST, Ross Kirsling
no flags Details | Formatted Diff | Diff
Patch (141.81 KB, patch)
2018-11-23 15:01 PST, Ross Kirsling
no flags Details | Formatted Diff | Diff
Patch (139.58 KB, patch)
2018-11-23 23:21 PST, Ross Kirsling
no flags Details | Formatted Diff | Diff
Patch (143.13 KB, patch)
2018-11-24 00:16 PST, Ross Kirsling
no flags Details | Formatted Diff | Diff
Patch (150.56 KB, patch)
2019-01-07 15:06 PST, Ross Kirsling
no flags Details | Formatted Diff | Diff
Patch for landing (150.68 KB, patch)
2019-05-20 15:30 PDT, Ross Kirsling
no flags Details | Formatted Diff | Diff
Patch for landing (151.55 KB, patch)
2019-05-20 17:55 PDT, Ross Kirsling
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ross Kirsling 2018-11-17 14:11:33 PST
Make unsigned LayoutUnit constructors explicit
Comment 1 Ross Kirsling 2018-11-17 14:14:59 PST
Created attachment 355205 [details]
Patch
Comment 2 Ross Kirsling 2018-11-17 17:43:07 PST
Created attachment 355215 [details]
Patch
Comment 3 Ross Kirsling 2018-11-17 18:01:07 PST
Turns out this patch is relatively small, as long as we leave LayoutUnit(int) implicit.

If this is acceptable, then I think bug 191538 can simply be closed.
Comment 4 EWS Watchlist 2018-11-17 18:35:18 PST Comment hidden (obsolete)
Comment 5 EWS Watchlist 2018-11-17 18:35:20 PST Comment hidden (obsolete)
Comment 6 EWS Watchlist 2018-11-17 18:44:46 PST Comment hidden (obsolete)
Comment 7 EWS Watchlist 2018-11-17 18:44:47 PST Comment hidden (obsolete)
Comment 8 EWS Watchlist 2018-11-17 18:49:31 PST Comment hidden (obsolete)
Comment 9 EWS Watchlist 2018-11-17 18:49:33 PST Comment hidden (obsolete)
Comment 10 EWS Watchlist 2018-11-17 19:09:06 PST Comment hidden (obsolete)
Comment 11 EWS Watchlist 2018-11-17 19:09:09 PST Comment hidden (obsolete)
Comment 12 Ross Kirsling 2018-11-19 23:57:26 PST
Created attachment 355317 [details]
Patch
Comment 13 EWS Watchlist 2018-11-20 00:50:38 PST Comment hidden (obsolete)
Comment 14 EWS Watchlist 2018-11-20 00:50:40 PST Comment hidden (obsolete)
Comment 15 EWS Watchlist 2018-11-20 00:56:52 PST Comment hidden (obsolete)
Comment 16 EWS Watchlist 2018-11-20 00:56:54 PST Comment hidden (obsolete)
Comment 17 Ross Kirsling 2018-11-20 23:51:49 PST
It seems I was a little confused earlier.

Although there are few cases of implicit LayoutUnit(unsigned) and LayoutUnit(double) in use, there are hundreds of cases of implicit LayoutUnit(float). The misleading part was that we can successfully compile without addressing them (since floats will end up using the implicit LayoutUnit(int) constructor), but naturally this has unpredictable effects on runtime behavior.

So to handle this properly without a decrease in ergonomics, we still need all of those templates, and definitely will want to introduce that "0_lu" literal first.
Comment 18 Ross Kirsling 2018-11-21 16:43:37 PST
Created attachment 355445 [details]
Patch
Comment 19 Ross Kirsling 2018-11-23 15:01:06 PST
Created attachment 355537 [details]
Patch
Comment 20 Ross Kirsling 2018-11-23 23:21:25 PST
Created attachment 355553 [details]
Patch
Comment 21 Ross Kirsling 2018-11-24 00:16:31 PST
Created attachment 355556 [details]
Patch
Comment 22 Ross Kirsling 2018-11-24 00:18:41 PST
The new title here is more accurate description of the sole benefit I can see to this: to ensure that conversions from float/double don't just magically happen.

We can do this by adding either templates or float overloads to LayoutPoint, LayoutSize, LayoutRect, and the like.
This patch demonstrates the former; the latter would be a somewhat larger patch.
Templates might be more opaque but they do support double, say, at the same time.

This patch is now just a third of the size of the original; I'm hoping it's reviewable as is, mainly since I'm not sure if anything in the patch would be desired independent of the motivation to make LayoutUnit explicit.

Outside of the templates, every change should involve constructing or converting a LayoutUnit lvalue from a float-valued expression, e.g.:
- LayoutUnit foo = ...;          => LayoutUnit foo { ... };
- return ...;                    => return LayoutUnit(...);
- std::max<LayoutUnit>(..., ...) => std::max(LayoutUnit(...), ...)
- LayoutPoint(..., ...)          => { LayoutUnit(...), ... }
Comment 23 Ross Kirsling 2018-11-24 00:34:51 PST
(Alternatively, if the consensus is that this isn't really an improvement, then please let me know and I will happily step aside. 😅)
Comment 24 Ross Kirsling 2018-11-25 16:41:02 PST
(In reply to Ross Kirsling from comment #22)
> We can do this by adding either templates or float overloads to LayoutPoint,
> LayoutSize, LayoutRect, and the like.
> This patch demonstrates the former; the latter would be a somewhat larger
> patch.
> Templates might be more opaque but they do support double, say, at the same
> time.

Sorry, my earlier explanation is kind of insufficient.

The real reason float overloads would be a larger patch and potentially undesirable going forward is because of cases like this:
> LayoutPoint(someLayoutUnit(), someInt())

The intention would be to have the int get implicitly converted to LayoutUnit (and use LayoutPoint(LayoutUnit, LayoutUnit)), but the compiler complains that it's actually ambiguous, since perhaps we wanted both parameters to be implicitly converted to float (and use LayoutPoint(float, float)).

Hence this effort really probably only makes sense with the template approach.

---

Furthermore, this effort doesn't work if we mark *everything but* LayoutUnit(int) as explicit, for the reason I mentioned in comment 17 -- if you forget to explicitly convert float to LayoutUnit, you won't get an error as desired; you'll just end up using implicit LayoutUnit(int) without realizing it, which is a strictly worse situation.

Given that we don't want to make LayoutUnit(int) explicit, since that particular implicit conversion is clearly a feature, then the best we could really do is *just* mark the lossy constructors as explicit (i.e. at least float and double; debatably also unsigned long [long], though they're unused anyway). That way, when you forget to convert float to LayoutUnit, the compiler asks "were you intending to use LayoutUnit(int) or LayoutUnit(unsigned) or...?"

And that's precisely the patch here.

---

Whether implicit lossy conversion from floating-point types is enough of a concern to justify all this...is a question for the reviewers.

(I kind of wish I could've reached that explanation without putting in the level of time and effort that I did, but hey, it's been educational. 😂)
Comment 25 Ross Kirsling 2018-12-01 16:45:42 PST
Any chance for a review here? :)

It may suffice to read comments 22 through 24; the code only needs to be read if the approach is deemed desirable.
Comment 26 Ross Kirsling 2018-12-10 17:04:41 PST
I'm guessing that the unspoken consensus here is a moderate preference for the status quo?

I'll tentatively plan to close this as WONTFIX at the end of the week unless I hear otherwise. :)
Comment 27 Simon Fraser (smfr) 2018-12-10 17:18:07 PST
I think this is a good change, but haven't had a chance to review it. I'd like to hear from Zalan.
Comment 28 Ross Kirsling 2018-12-10 17:27:01 PST
(In reply to Simon Fraser (smfr) from comment #27)
> I think this is a good change, but haven't had a chance to review it. I'd
> like to hear from Zalan.

Cool! Sorry for assuming prematurely. 😅
Comment 29 Konstantin Tokarev 2018-12-18 10:11:01 PST
If we want to make float to integer conversion explicit in terms of floor/ceil/round/truncate, I think we should have ctor LayoutUnit(floor, ConversionPolicy) here and no operator=(floor)
Comment 30 zalan 2018-12-23 17:15:54 PST
(In reply to Simon Fraser (smfr) from comment #27)
> I think this is a good change, but haven't had a chance to review it. I'd
> like to hear from Zalan.
I've been wanting to do this but never had a chance (and didn't have a compelling reason to introduce such an intrusive change). I don't mind landing this.
Comment 31 Ross Kirsling 2019-01-07 15:03:07 PST
(In reply to Konstantin Tokarev from comment #29)
> If we want to make float to integer conversion explicit in terms of
> floor/ceil/round/truncate, I think we should have ctor LayoutUnit(floor,
> ConversionPolicy) here and no operator=(floor)

There are a couple of cons to this approach:

1. All of LayoutUnit's constructors clamp to int, so it seems quite natural/unambiguous that operator=(float) would follow suit.

2. The introduction of operator=(float) was aiming to reduce both the size of the diff and the burden of using these explicit constructors -- in particular, there are about 120 existing locations that would need to be updated.

(In reply to zalan from comment #30)
> (In reply to Simon Fraser (smfr) from comment #27)
> > I think this is a good change, but haven't had a chance to review it. I'd
> > like to hear from Zalan.
> I've been wanting to do this but never had a chance (and didn't have a
> compelling reason to introduce such an intrusive change). I don't mind
> landing this.

Thanks Zalan!

I'll upload a rebased version of the current patch.
Comment 32 Ross Kirsling 2019-01-07 15:06:56 PST
Created attachment 358535 [details]
Patch
Comment 33 Ross Kirsling 2019-02-06 18:53:17 PST
Any further thoughts here perchance?
Comment 34 Ross Kirsling 2019-05-19 15:53:30 PDT
Ping?

Happy to give this another rebase if there's still interest.
Comment 35 Antti Koivisto 2019-05-20 12:56:24 PDT
r=me
Comment 36 Ross Kirsling 2019-05-20 15:30:35 PDT
Created attachment 370273 [details]
Patch for landing
Comment 37 Ross Kirsling 2019-05-20 17:55:50 PDT
Created attachment 370288 [details]
Patch for landing
Comment 38 WebKit Commit Bot 2019-05-20 18:36:18 PDT
Comment on attachment 370288 [details]
Patch for landing

Clearing flags on attachment: 370288

Committed r245543: <https://trac.webkit.org/changeset/245543>
Comment 39 WebKit Commit Bot 2019-05-20 18:36:20 PDT
All reviewed patches have been landed.  Closing bug.
Comment 40 Radar WebKit Bug Importer 2019-05-20 18:37:20 PDT
<rdar://problem/50969679>