<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://www.w3.org/Bugs/Public/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4"
          urlbase="https://www.w3.org/Bugs/Public/"
          
          maintainer="sysbot+bugzilla@w3.org"
>

    <bug>
          <bug_id>24367</bug_id>
          
          <creation_ts>2014-01-22 20:57:55 +0000</creation_ts>
          <short_desc>Behaviour of URLUtils.searchParams setter</short_desc>
          <delta_ts>2014-03-19 13:55:35 +0000</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WHATWG</product>
          <component>URL</component>
          <version>unspecified</version>
          <rep_platform>PC</rep_platform>
          <op_sys>Windows NT</op_sys>
          <bug_status>RESOLVED</bug_status>
          <resolution>FIXED</resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords></keywords>
          <priority>P2</priority>
          <bug_severity>normal</bug_severity>
          <target_milestone>Unsorted</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter>sof</reporter>
          <assigned_to name="Anne">annevk</assigned_to>
          <cc>d</cc>
    
    <cc>erik.arvidsson</cc>
    
    <cc>mike</cc>
          
          <qa_contact>sideshowbarker+urlspec</qa_contact>

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>98903</commentid>
    <comment_count>0</comment_count>
    <who name="">sof</who>
    <bug_when>2014-01-22 20:57:55 +0000</bug_when>
    <thetext>The spec currently requires that upon setting URLUtils.searchParams with a URLSearchParams object with an existing &quot;url object&quot; association, it should create a copy of that object,

 http://url.spec.whatwg.org/#dom-url-searchparams

Hence,

  var url = new URL(&quot;...&quot;);
  var us = new URLSearchParams(&quot;a=b&quot;);

  // url object is not set for &quot;us&quot;, assign it as &quot;url&quot;&apos;s query object.
  url.searchParams = us;

  us.set(&quot;a&quot;, &quot;c&quot;);
  // us.set() observable.
  assert_equals(url.search, &quot;?a=c&quot;);

  // url object is set for &quot;us&quot;, copy it (and clear &quot;us&quot;&apos; url object connection.)
  url.searchParams = us;

  us.set(&quot;a&quot;, &quot;d&quot;);
  // us.set() not observable.
  assert_equals(url.search, &quot;?a=c&quot;);

  // url object not set for &quot;us&quot;, assign it as &quot;url&quot;&apos;s query object.
  url.searchParams = us;
  us.set(&quot;a&quot;, &quot;e&quot;);
  // us.set() observable (again.)
  assert_equals(url.search, &quot;?a=e&quot;);

Should the semantics of re-setting the query object via URLUtils.searchParams be different, or is this intended?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99011</commentid>
    <comment_count>1</comment_count>
    <who name="Erik Arvidsson">erik.arvidsson</who>
    <bug_when>2014-01-24 16:39:20 +0000</bug_when>
    <thetext>Sigbjørn, I find the current behavior a bit confusing.

I think we should just create a copy on assign. It just makes the semantics clear. And I believe that is what the spec says?

This is the behavior I want.

var url = new URL(&quot;http://example.com/?a=b&quot;);
var us = url.searchParams;
us.set(&quot;a&quot;, &quot;c&quot;);
assert_equals(url.search, &quot;?a=c&quot;);

url.searchParams = us; // us is now disconnected from url
us.set(&quot;a&quot;, &quot;d&quot;);
assert_equals(url.search, &quot;?a=c&quot;);
assert_equals(us.toString(), &quot;a=d&quot;);

If we do not disconnect it we get into strange cases when it is assigned to multiple urls.

(Firefox seems to ignore the set if the searchParams is set to the existing searchParams.)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99013</commentid>
    <comment_count>2</comment_count>
    <who name="">sof</who>
    <bug_when>2014-01-24 16:50:08 +0000</bug_when>
    <thetext>The spec does not allow copying if the &quot;url object&quot; of the URLSearchParams isn&apos;t set (step 3 and 4),

  http://url.spec.whatwg.org/#dom-url-searchparams

It could either always copy, or only copy in step 3 if the assigned object differs from the current one.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99015</commentid>
    <comment_count>3</comment_count>
    <who name="">sof</who>
    <bug_when>2014-01-24 17:05:32 +0000</bug_when>
    <thetext>FWIW, I&apos;m fine with either :) (including not having URLSearchParams as something separately constructable.)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99017</commentid>
    <comment_count>4</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-01-24 18:00:09 +0000</bug_when>
    <thetext>Mostly copying makes sense to me. Should we special case when you assign the same object? I.e. when you do url.searchParams = url.searchParams? Not copying in that case would make sense to me.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99019</commentid>
    <comment_count>5</comment_count>
    <who name="Erik Arvidsson">erik.arvidsson</who>
    <bug_when>2014-01-24 18:06:08 +0000</bug_when>
    <thetext>I prefer not special casing. It leads to more things to remember and you cannot look at the code to see what is going on.

function f(url, params) {
  url.searchParams = params;
  params.set(&apos;a&apos;, &apos;b&apos;); // mutates url or not?
}</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99020</commentid>
    <comment_count>6</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-01-24 18:17:29 +0000</bug_when>
    <thetext>Fair.

baku suggested on IRC to let a URLSearchParams be associated with many URL objects. As that seemed closer to JavaScript. The problem with that is that then you need to update many URL objects if your URLSearchParams changes (and maybe they need to do that in order if it becomes observable).</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99021</commentid>
    <comment_count>7</comment_count>
    <who name="">sof</who>
    <bug_when>2014-01-24 18:26:45 +0000</bug_when>
    <thetext>arv&apos;s example convinced me; simple &amp; functional.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99023</commentid>
    <comment_count>8</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-01-24 19:19:23 +0000</bug_when>
    <thetext>Domenic also argued for what baku suggested. The reason is that then you preserve

  x.y = z
  x.y === z


That would mean that whenever we assign a URLSearchParams to a URL, we&apos;d do something like this:

1. If URL already has an associated URLSearchParams, remove URL from that URLSearchParams.

2. Add URL to the new URLSearchParams

And whenever a URLSearchParams is updated we iterate through its URLs and update each in turn.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99024</commentid>
    <comment_count>9</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-01-24 19:19:58 +0000</bug_when>
    <thetext>The example in comment 5 would then always result in mutating.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99027</commentid>
    <comment_count>10</comment_count>
    <who name="Erik Arvidsson">erik.arvidsson</who>
    <bug_when>2014-01-24 20:57:33 +0000</bug_when>
    <thetext>(In reply to Anne from comment #8)
&gt; And whenever a URLSearchParams is updated we iterate through its URLs and
&gt; update each in turn.

That is how most JS implementations would work. I&apos;m fine with that too even though it is a bit more complex to implement on the C++ side.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99028</commentid>
    <comment_count>11</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-01-24 21:26:40 +0000</bug_when>
    <thetext>Ok. I will make it like that then. I might not get this fixed for a few weeks so please proceed assuming comment 8 is part of the standard.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99030</commentid>
    <comment_count>12</comment_count>
    <who name="">sof</who>
    <bug_when>2014-01-24 21:31:33 +0000</bug_when>
    <thetext>I&apos;m struggling to see the need for such generality.

One way to sidestep all of this is to make url.searchParams a readonly attribute, and remove all the URLParams constructors. You can then (only) use url.searchParams to manipulate the query portion of one URL.

If you want to copy the query portion from one URLUtils-implementing object to another, use url.search.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99031</commentid>
    <comment_count>13</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-01-24 21:40:11 +0000</bug_when>
    <thetext>If we offer url.searchParams.replaceWith(new URLSearchParams(...)) or some such that might be okay too. Hmm...</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99032</commentid>
    <comment_count>14</comment_count>
    <who name="Erik Arvidsson">erik.arvidsson</who>
    <bug_when>2014-01-24 21:43:14 +0000</bug_when>
    <thetext>(In reply to Anne from comment #13)
&gt; If we offer url.searchParams.replaceWith(new URLSearchParams(...)) or some
&gt; such that might be okay too. Hmm...

Ugh.

Here are the options

1. Copy on assign
2. Keep references to multiple owners
3. Read only (you can always use .search)

in the order I prefer.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99036</commentid>
    <comment_count>15</comment_count>
    <who name="Domenic Denicola">d</who>
    <bug_when>2014-01-24 22:48:02 +0000</bug_when>
    <thetext>I think copy on assign is kind of wonky, as it doesn&apos;t match normal semantics of assigning to a property. (I.e., those you expect from a data property.) Yes, the web platform has (ab)used setters to make assignment mean some pretty different things in the past, but I personally would prefer to keep the semantics as much as possible.

That&apos;s why &quot;Keep references to multiple owners&quot; seems best.

After that I think non-writable searchParams + `url.searchParams.replaceWith(new URLSearchParams(...))` is pretty decent. But if Arv doesn&apos;t like it, then I think the liked-or-at-least-tolerated-by-everyone option is indeed &quot;Keep references to multiple owners.&quot;</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99499</commentid>
    <comment_count>16</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-01-30 21:22:10 +0000</bug_when>
    <thetext>https://github.com/whatwg/url/commit/c9904d891ef9ce23f94206f94e8550f4a6f4b31f</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>99553</commentid>
    <comment_count>17</comment_count>
    <who name="">sof</who>
    <bug_when>2014-01-31 22:07:15 +0000</bug_when>
    <thetext>That was quick! One potential user pitfall here is aliasing vs copying, i.e.,

 url2.searchParams = url1.searchParams;

vs

 url2.searchParams = new URLSearchParams(url1.searchParams);

I still don&apos;t understand the use for 1-N associations, but ok.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>102321</commentid>
    <comment_count>18</comment_count>
    <who name="">sof</who>
    <bug_when>2014-03-13 21:54:47 +0000</bug_when>
    <thetext>According to the current spec text, the following holds: 

  var usp = new URLSearchParams();
  url.searchParams = usp;
  url.searchParams = null;
  usp.set(&quot;a&quot;, &quot;b&quot;);
  assert_true(&quot;?a=b&quot;, url.searchParams.search);

i.e., &quot;url.searchParams = null;&quot; has no effect, unlike &quot;url.search = &apos;&apos;;&quot; (or &quot;url.searchParams = new URLSearchParams();&quot;)

As intended, or should the setter steps for http://url.spec.whatwg.org/#dom-url-searchparams be re-ordered a bit for the null case?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>102352</commentid>
    <comment_count>19</comment_count>
    <who name="">sof</who>
    <bug_when>2014-03-14 07:04:50 +0000</bug_when>
    <thetext>(In reply to sof from comment #18)
&gt; According to the current spec text, the following holds: 
&gt; 
..
&gt;   assert_true(&quot;?a=b&quot;, url.searchParams.search);
&gt; 

Typo, should have been: assert_true(&quot;?a=b&quot;, url.search);</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>102548</commentid>
    <comment_count>20</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-03-18 11:30:08 +0000</bug_when>
    <thetext>So what effect do you think it should have? If we had different signatures for set and get I would allow returning null but not setting to null. So maybe it should throw a TypeError instead?</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>102573</commentid>
    <comment_count>21</comment_count>
    <who name="">sof</who>
    <bug_when>2014-03-18 16:05:50 +0000</bug_when>
    <thetext>I guess I need to understand why the attribute is nullable to start with to answer that. Could you explain, please? :)</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>102602</commentid>
    <comment_count>22</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-03-18 19:19:50 +0000</bug_when>
    <thetext>I think it was nullable because at one point not all URLs had a query. That changed, so we should change the API too (to not be nullable).</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>102630</commentid>
    <comment_count>23</comment_count>
    <who name="Anne">annevk</who>
    <bug_when>2014-03-19 13:48:33 +0000</bug_when>
    <thetext>https://github.com/whatwg/url/commit/3069fa45acb8134cc0c722ea548992e844b2d240</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>102632</commentid>
    <comment_count>24</comment_count>
    <who name="">sof</who>
    <bug_when>2014-03-19 13:55:35 +0000</bug_when>
    <thetext>That takes care of it from here; thank you.</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>