locutusjs / locutus

Bringing stdlibs of other programming languages to JavaScript for educational purposes
https://locutus.io
MIT License
3.73k stars 1.12k forks source link

Array issues #148

Closed kukawski closed 8 months ago

kukawski commented 10 years ago

I created this ticket as a continuation of issue #27 to discuss a strategy for handling arrays.

Some of our functions work properly with pure arrays, but fail on objects, because in some browsers key order is not preserved. I know that Brett has done some work on "custom" arrays (array wrapper function). And I think it could be the proper way if not some browser limitations. I have a strong believe that ES6 Proxies could really help here.

But all in all, we should discuss our strategy, so we have one strategy and everyone of us understands what we want to achieve and how to mark functions that fail for some conditions.

kvz commented 10 years ago

Thank you! Commenting on what Brett said in #27:

Not sure if you were aware of this, Kevin, but the iteration order problem is not limited to reusing deleting properties in IE--it has been happening in Chrome (and not sure whether I may have seen this in FF too): https://code.google.com/p/v8/issues/detail?id=164 . That is why I started all that work in array() to allow, with configuration, the style:

array({key1: value1}, {key2: value2});

...for something looking more like associative arrays but can retain iteration order, e.g., when the functions aware of this structure are called on it (and this structure also supports more JavaScript-friendly jQuery-style chaining syntax).

It is, imo, not just a hack but a practical workaround, even if it would be easier (and less of a source of confusion) than had iteration order been made reliable across platform by the browsers.

I also think it is something we can educate users about if we provide them a working alternative rather than the pretension that the existing way is going to work. I did add notes to this effect in at least some of the array functions as I recall, but I also did not finish the work on allowing arrays to support the alternative syntax (so not all are ready even if you wanted to support this way).

Anyways, that's just my two cents, but if you want to remove support for the alternative syntax, I'd suggest moving all array functions (or those that rely on iteration order) into the experimental section. We might get some commotion from that, but perhaps that would be good if people are using them thinking they are working cross-platform.

I realise that we can forget about ordered objects.

I'm just trying to think if we should accept this as a shortcoming of php.js so that:

We would admit in a note in every array function that if the user cares about the ordering of the objects, php.js is not the right choice. We would just accept it as a concession.

The other route is what Brett started. Although I feel a structure like:

array({key: key1, val: value1}, {key: key2, val: value2});

might offer more flexibility.

@kukawski ES6 Proxies look promising but it will probably take some time before support is wide-spread enough that we can actually use it?

brettz9 commented 10 years ago

Thank you, Rafał, for starting a separate issue on this. In support of your idea for a single strategy, I might just make explicit that if we did change the approach to NOT treat objects as arrays, then this ought also be streamlined for functions such as gettype and is_array().

You say, "And I think it could be the proper way if not some browser limitations.". What browser limitations do you mean?

Proxies might help ensure that properties dynamically added after object creation were iterated in a fixed order, I suppose. Any others you were thinking of?

Even with proxies, however, I think we should still decide on a convenient initialization syntax (which is hopefully better than arr.set(key, val)).

I prefer either:

array({key1: value1}, {key2: value2}); or array([key1, value1], [key2: value2]);

...though I think the former is better because it avoids the need for quotes around keys and because it better conjures up the idea of an associative array with two items associated together.

Why do you like the following structure, Kevin?

array({key: key1, val: value1}, {key: key2, val: value2});

I know jQuery uses a similar approach with https://api.jquery.com/serializeArray/ (using name and value as its keys).

While the structure you mention might be more streamlined as far as accessing values on the seed objects in the same manner, I think this would not be very important since one should be able to do all the accessing necessary on the resultant array()-created object instead. Am I missing something else?

I also see that it may enforce a little less ambiguity in that it may make more clear that this is not a numeric array with a series of one-key objects, but even this protection is not perfect (someone may indeed want a numeric array of key/val objects).

Regardless, imo, the more cumbersome syntax you mention would need to have quite compelling use cases in order to justify forcing users into using a longer and more cumbersome format when I think the main attraction here is providing an easy and readable route to ordered maps (which was ideally as close to PHP as possible as well).

kvz commented 8 years ago

I'm currently leaning towards:

For cases like is_array, I'd say JavaScript datatypes are first class citizens, meaning it shall return false on {} and true on [], which the exception for when iniVal evaluates to 'on' in:

var iniVal = (typeof require !== 'undefined' ? require('../info/ini_get')('locutus.objectsAsArrays') : undefined) || 'on'

Likewise, sort functions shall accept {} when this setting is active.

Thoughts?