profile
viewpoint
Matt Kane ascorbic @VelaLabs @gatsbyjs UK mk.gg @Gatsbyjs core team

ascorbic/clevrlib 15

CLEVR Actionscript Library

ascorbic/canvas-paint-tool 6

Realistic canvas paint tool

ascorbic/airbed 5

Lightweight CouchDB client library for Adobe AIR

ascorbic/actionscript3-tmbundle 1

ActionScript 3 TextMate Bundle

ascorbic/babel-jsx-utils 1

Utilities for working with Babel and JSX

ascorbic/core-plot 1

Unofficial core-plot mirror

ascorbic/doctrine-tracker 1

Just a tracker for the Doctrine svn server, so I can add it as a submodule in my /vendor/ project

startedascorbic/canvas-paint-tool

started time in 5 days

startedascorbic/babel-jsx-utils

started time in 20 days

issue commenttc39/proposal-record-tuple

Box: choosing between manual boxing and automatic boxing

I agree that this case is a significant ergonomic risk. We'd be depending on linters and type systems, rather than early errors, to catch these cases, as it would be too weird to allow arbitrary expressions but just not object literals in this space.

Note that, in a previous version of this proposal, we actually did interpret this as nested Records and Tuples, so I see how this could be confusing. At the same time, I'm not really persuaded by the expectation that things would be coerced to primitives: we don't really have that kind of coercion in the language in general. It will always be possible to claim various expectations, for any proposal, no matter what semantics we decide.

rricard

comment created time in a month

issue commenttc39/proposal-record-tuple

Box: choosing between manual boxing and automatic boxing

That seems like a footgun tho with explicit boxing - I doubt anyone would provide an object literal, and expect it to be coerced to a primitive.

rricard

comment created time in a month

issue commenttc39/proposal-record-tuple

Box: choosing between manual boxing and automatic boxing

Syntactically record properties can be any expression, currently (with explicit boxing) the only restriction is that they evaluate to a primitive.

rricard

comment created time in a month

issue commenttc39/proposal-record-tuple

Box: choosing between manual boxing and automatic boxing

I thought that syntactically, #{ server: { port: 1234 } } would be an error? Even with automatic boxing I think this should be the case. With automatic boxing I'd expect something more like const obj = { port: 1234 }; #{ server: obj } to be necessary.

rricard

comment created time in a month

issue commenttc39/proposal-record-tuple

Storing objects inside Record & Tuple with `Box`?

@Jack-Works it is not exactly the case, there are ergonomics tradeoffs discussed in #206.

rickbutton

comment created time in a month

issue commenttc39/proposal-record-tuple

Storing objects inside Record & Tuple with `Box`?

If so, I think there is no need to introduce the "Box", make tuple and records be able to store mutable objects are the same effect with this approach.

rickbutton

comment created time in a month

issue commenttc39/proposal-record-tuple

Storing objects inside Record & Tuple with `Box`?

Boxes are identical if given the same object:

const obj = {};
const obj2 = {};
Box(obj) === Box(obj)
Box(obj) !== Box(obj2)
rickbutton

comment created time in a month

issue commenttc39/proposal-record-tuple

Box: choosing between manual boxing and automatic boxing

As a downside I see in automatic boxes, is that #{ server: { port: 1234 } } === #{ server: { port: 1234 } } is false because the two { port: 1234 } objects are different, and while reading the code it's easy to miss that they aren't records.

I can concur this is a very problematic issue and has been noted by many people I talked to about this issue.

rricard

comment created time in a month

issue commenttc39/proposal-record-tuple

Box: choosing between manual boxing and automatic boxing

We actually discussed Record.containsBoxes as an alternative naming with @littledan. I am going to change it in the issue.

rricard

comment created time in a month

issue commenttc39/proposal-record-tuple

Storing objects inside Record & Tuple with `Box`?

If boxes aren't identical in the comparing, what difference between support mutable value in records and tuples directly?

rickbutton

comment created time in a month

issue commenttc39/proposal-record-tuple

Box: choosing between manual boxing and automatic boxing

Yes, Record.containsBoxes makes much more sense to me as a name, thanks.

rricard

comment created time in a month

issue commenttc39/proposal-record-tuple

Box: choosing between manual boxing and automatic boxing

The idea behind Box.contains is that it should check if the parameter is a record containing mutable state (draft spec: https://github.com/tc39/proposal-record-tuple/pull/197/files#diff-9845cd5af38a2d508fce723eb3df23019f4e2578b2a5b75e96e56db532b883f6R676). Maybe it the name was Record.containsBoxes(record) the example would be clearer?

rricard

comment created time in a month

issue commenttc39/proposal-record-tuple

Storing objects inside Record & Tuple with `Box`?

Just a fact check.

#{ item: Box(alert) } === #{ item: Box(confirm) }

Should be true right? Boxes are treated as identical discarding what it contains otherwise the VDOM case is not working

This isn't what I would expect. Shouldn't every Box you create be unique and !== to every other Box?

const alertBox = Box(alert);
const confirmBox = Box(confirm);
#{ item: alertBox } === #{ item: alertBox } // => true, because records have the same shape and the same content
#{ item: alertBox } === #{ item: confirmBox} // => false, because records have the same shape but not the same content
#{ item: alertBox } === #{ item: Box(alert)} // => false, box identity is not based on its contents
rickbutton

comment created time in a month

issue commenttc39/proposal-record-tuple

Box: choosing between manual boxing and automatic boxing

I'm confused; why would Box.contains(record) be true when record isn't a box, and fn is the Boxed thing? What is Box.contains supposed to do?

rricard

comment created time in a month

issue openedtc39/proposal-record-tuple

Box: choosing between manual boxing and automatic boxing

This issue is a direct follow-on of #200 and expands the following open question from the original issue:

Should you be required to "unbox" a Box inside a Record or Tuple, or should it be "automatic" in some way?

It also, for the sake of simplifying things, will not require you to create a Box, it will be created for you.

Essentially, we need to choose between two options:

  • Manual/explicit

    const record = { fn: Box(fn) };
    Box.contains(record); // => true
    record.fn(); // => TypeError
    record.fn.unbox()();
    typeof record.fn // => "box"
    typeof record.fn.unbox() // => "function"
    const config = #{ server: { port: 1234 } }; // => TypeError
    
  • Automatic/implicit

    const record = { fn };
    Box.contains(record); // => true
    record.fn();
    typeof record.fn // => "function"
    const config = #{ server: { port: 1234 } }; // => Ok
    

I have the intuition that forcing manual and explicit boxing helps with making sure that nothing gets mutated unless we see the use of .unbox(). Those guarantees are interesting in many cases, especially when dealing with business logic in large codebases. This is something that we found could greatly reduce bugs at the boudary between immutable and mutable domains and that we think could be beneficial for the majority of users of the feature.

However, manual boxing is verbose and is cumbersome when used often. Automatic boxing would be terser.

I think that the ergonomic tradeoff of manual boxing is worth it to reduce potential bugs but I'm interested in discussing what you think about it!

created time in a month

issue commenttc39/proposal-record-tuple

Equality semantics for `-0` and `NaN`

I'm comfortable saying that this justifies increased complexity.

bakkot

comment created time in a month

issue commenttc39/proposal-record-tuple

Equality semantics for `-0` and `NaN`

We just had a meeting with some V8 folks about performance, and I wanted to document some thoughts re: SameValueZero comparison on this issue thread.

Specifically, the thinking is that using "recursive SameValueZero" comparison for === for Record/Tuple might make equality checking complex. If === produced reliable comparison for "observably equal" Records/Tuples (i.e. what Object.is does), then interning becomes more straightforward (since you would be able to swap one of the equality operands out for the other without managing a "set" of things that are equal, some with -0 and some with +0). This complexity doesn't strictly prevent us from choosing SameValueZero, but does certainly increase engine complexity for engines that wish do to interning or other equality optimizations.

bakkot

comment created time in a month

issue closedtc39/proposal-record-tuple

Can compound primitives be used as object keys?

<!-- Welcome!

  • [✔️] My issue is not a duplicate
  • [✔️] My issue relates to the Records and Tuples proposal and not a follow-on proposal --> I was wondering whether these compound primitives, especially Tuples, could be used as object keys, similarly to how tuples can be used as dictionary keys in Python. The big difference to me vs. plain arrays and objects as keys is the equality-by-value property.

Has this been considered or discussed at all? The main possible issue I see is with JSON compatibility, but the same is already true of Symbol keys; perhaps compound primitive keys would simply be ignored by JSON.stringify().

Thoughts?

closed time in a month

kenbellows

issue commenttc39/proposal-record-tuple

Can compound primitives be used as object keys?

Just realized I never responded. Yes, Maps are generally fine for practical purposes, and probably better in many cases for performance and other reasons. I mostly just miss the syntactic elegance of Python's tuple keys in dictionary literals. Honestly the Map constructor syntax isn't far off anyway:

const orders = new Map([
  [ \#['user123', 'order456'], { items: [...], ...} ],
  [ \#['user142', 'order857'], { items: [...], ...} ],
  ...
])

I'm satisfied, I was more curious if the conversation had come up.

kenbellows

comment created time in a month

created repositoryensdomains/l2gateway-demo

A simple demonstration of a proposed L2 gateway specification

created time in a month

startedascorbic/create-test

started time in a month

issue commenttc39/proposal-record-tuple

Performance expectations (implementers and JS developers)

I would expect performance gains and fewer bugs e.g. in React when React would use Records for its props. A lot of rerenders could be skipped when react just compares the records by identity. This would eliminate the need for manual memoization in many cases in React projects too.

littledan

comment created time in a month

issue closedtc39/proposal-record-tuple

Use cases where we need fast equality comparison?

One of the discussion points of the proposal has been making equality comparison fast. But which use cases need it?

The thought process goes like this:

  1. We can achieve fast equality comparisons by internalizing.

  2. Maybe we shouldn't internalize upfront on creation, since not all records / tuples will be equality-compared.

  3. So let's internalize when we do the first equality comparison.

  4. But do we ever do equality comparisons where both objects are "old"?

E.g., if we have a big state object rec_a, and we compare it against rec_b (with structural sharing), to figure out whether the state has changed. Then we throw one of them away. Say we keep rec_b. Then later we compare it against a new one rec_c, etc.

By having internalized any of them, we can't make the equality comparison any faster. Either we traverse (*) the new one to internalize it eagerly, or we traverse (*) it to internalize it lazily, or we don't internalize at all but traverse (*) it when doing the equality comparison.

(*) We only need to traverse until we hit the structurally shared part of the record / tuple. This holds for all the options.

  1. Are there some other use cases which would benefit from fast equality? Alternatively, what are we missing?

(Kudos to @camillobruni and @LeszekSwirski for coming up with this thought process.)

closed time in a month

marjakh

issue commenttc39/proposal-record-tuple

Use cases where we need fast equality comparison?

@jridgewell thanks for pointing out the wrong assumption (of maximal structural sharing) (sorry for the delay)

marjakh

comment created time in a month

issue closedtc39/proposal-record-tuple

How deep is "deeply immutable," in regards to records and tuples?

  • [ * ] My issue is not a duplicate
  • [ * ] My issue relates to the Records and Tuples proposal and not a follow-on proposal

The proposal is only allowing nested immutability to prevent mixing mutable and immutable structures, yet primitives have functions in their prototypes, which are mutable objects. Does this cause a problem?

const list = #[ "item0" ];

list[0].toString.foo = Math.random();

it would appear that this ^ level of immutability is fundamentally unachievable in ECMAScript.

closed time in 2 months

00ff0000red

issue commenttc39/proposal-record-tuple

How deep is "deeply immutable," in regards to records and tuples?

Thank you for clarifying the exact aim of the proposal. I for one would genuinely like to see complete immutability introduced to the language, and consider it very unfortunate that JavaScript is as dynamic and forgiving as it is.

But maybe what you said could be used as an argument for giving Records and Tuples a prototype?

00ff0000red

comment created time in 2 months

PR opened ascorbic/rebuild-contentful-test

Bump object-path from 0.11.4 to 0.11.5

Bumps object-path from 0.11.4 to 0.11.5. <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/mariocasciaro/object-path/commits">compare view</a></li> </ul> </details> <br />

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


<details> <summary>Dependabot commands and options</summary> <br />

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
  • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
  • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
  • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the Security Alerts page.

</details>

+3 -3

0 comment

1 changed file

pr created time in 2 months

more