Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reintroduce +++ operator to mean concatenation with mutation #1111

Open
determin1st opened this issue Sep 5, 2020 · 16 comments
Open

Reintroduce +++ operator to mean concatenation with mutation #1111

determin1st opened this issue Sep 5, 2020 · 16 comments
Labels

Comments

@determin1st
Copy link

determin1st commented Sep 5, 2020

Can you tell why deprecate +++ operator? It doesn't mess with ++ right, must be the same precendence with ++, so could be "recovered" easily? Any story about it maybe :]

my "projected" use-case:

# inside of object constructor function...
# ...
	@item = item = {} # all
	@list = list = [root] # all ordered
	####
	list +++ (querySelectorChildren box, '.item')
	a = -1
	while ++a < list.length
		if b = querySelectorChild list[a], '.section'
			list +++ (querySelectorChildren b, '.item')
# ...
# end of example
@rhendric
Copy link
Collaborator

rhendric commented Sep 5, 2020

It's just been renamed to  ++  (note the spaces; unspaced ++ is increment). Your example works if you replace all the +++ with ++= (you need the = because  ++  doesn't mutate the lists, it only returns their concatenation).

@rhendric rhendric closed this as completed Sep 5, 2020
@determin1st
Copy link
Author

ye, i figured only ++ won't go, so thanks, didn't know about ++=, will check

@determin1st
Copy link
Author

determin1st commented Sep 5, 2020

one more thing about it (generated from ++=):

      while (++a < list.length) {
        if (b = querySelectorChild(list[a], '.section')) {
          list = list.concat(querySelectorChildren(b, '.item'));
        }

the assignment is not needed, right, should be only list.concat(..)

@rhendric
Copy link
Collaborator

rhendric commented Sep 5, 2020

@determin1st
Copy link
Author

oh, my, i've missed the bug then..

any chance to resurrect +++ from the imperative hell?

@vendethiel
Copy link
Contributor

+++ did exactly the same as ++ does

@determin1st
Copy link
Author

determin1st commented Sep 6, 2020

maybe let's tweak it to Array.splice ? so it will mutate the left operand? i mean new +++ with .splice

@vendethiel
Copy link
Contributor

Why? just use ++=

@determin1st
Copy link
Author

because +++ is a sister of <<<

with ++= i have to follow this path:

# ...
	item = {} # all
	list = [root] # all ordered
	####
	list ++= (querySelectorChildren box, '.item')
	a = -1
	while ++a < list.length
		if b = querySelectorChild list[a], '.section'
			list ++= (querySelectorChildren b, '.item')
	# assign one more time :(
	@item = item
	@list = list
# ...

see, i could assign it one-line at the top, have to add 2 more lines.
with the .splice as +++ it would be

# ...
	@item = item = {} # all
	@list = list = [root] # all ordered
	####
	list +++ (querySelectorChildren box, '.item')
	a = -1
	while ++a < list.length
		if b = querySelectorChild list[a], '.section'
			list +++ (querySelectorChildren b, '.item')
# ...

makes sense?

@ceremcem
Copy link

ceremcem commented Sep 6, 2020

@determin1st Why can't you use @list and @item during the operations?

# ...
	@item = {} # all
	@list = [root] # all ordered
	####
	@list ++= (querySelectorChildren box, '.item')
	a = -1
	while ++a < @list.length
		if b = querySelectorChild @list[a], '.section'
			@list ++= (querySelectorChildren b, '.item')
# ...

What is wrong with above code?

@rhendric
Copy link
Collaborator

rhendric commented Sep 7, 2020

IMO, if you want to mutate an array by appending new elements, you should just call .push on it. This is subjective, but based on experience with similarly-spelled operators I wouldn't expect an expression spelled a +++ b to mutate a, or even treat a and b fundamentally differently.¹ a <<< b is at least visually asymmetric enough to hint at the side effect. I know LiveScript has a whole mess of operators, but I don't think more operators need to be introduced just as aliases to methods. a.push ...b is much clearer about what's going on, is already familiar to every JavaScript programmer, and is, what, 9 characters instead of 5? Not exactly a huge downside. It doesn't look as mathematical, but since what's happening isn't a mathematical concatenation but rather an impure mutation, I think that's a positive.

  1. In Haskell, which is the only language I know with a +++ operator in the core library, +++ is a way to combine functions²; f +++ g is a function that can take a value tagged Left and apply f to it, or a value tagged Right and apply g to it. Haskell's ++ operator means the same thing as in LiveScript.
  2. Well, arrows, but anyone who needs this explanation probably doesn't need to worry about the difference.

@rhendric rhendric reopened this Sep 7, 2020
@rhendric rhendric changed the title about removal of +++ Reintroduce +++ operator to mean concatenation with mutation Sep 7, 2020
@determin1st
Copy link
Author

determin1st commented Sep 8, 2020

@ceremcem well ye, i only wanted a bit of perfectionism, that can be done in multiple ways, but somehow +++ appeared as a natural thing when i wrote the initializer's code.

@rhendric 9 characters plus engine implementation dependent, can't say how much arguments allowed to push(...b), i mean just a loop would be more solid and maybe faster

@rhendric
Copy link
Collaborator

rhendric commented Sep 8, 2020

Which implementations don't support push with multiple arguments? It's in the ES3 spec, which is the version of JS that LiveScript nominally targets as a baseline when not using features that more or less explicitly require more modern engines, like generators and promises.

@determin1st
Copy link
Author

i mean here, the "Merging two arrays" section:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push

says:

Do not use this method if the second array (moreVegs in the example) is very large because the maximum number of parameters that one function can take is limited in practice. See apply() for more details.

i checked the limit was 65535 for the second array in Chromium. Sure, it's hard to reach but still..

@rhendric
Copy link
Collaborator

rhendric commented Sep 9, 2020

.splice is presumably subject to the same limitation, right? So if this matters to you, the only viable approach would be to use (either manually, or have some syntax compile into) a loop. But I'm guessing that for such large arrays, .concat would be faster than a loop, so the best thing for large arrays would be ++= and the best thing for small arrays would be .push .... Since PureScript can't know how big your arrays are, the programmer has to select the best approach. So I think you would need to make the case that whatever +++ would compile to is better than .push ... for small arrays, or better than ++= for large arrays. What do you think about that?

@determin1st
Copy link
Author

determin1st commented Sep 10, 2020

i thought that .splice takes array as an argument first, it doesn't, so it doesn't fit.

i've made some tests:
http://jsbench.github.io/#482b62ecdddfeffcea89d30ded47adb6

so, by the number of elements (in the second array):

20: loop is 18% faster
200: push is 38% faster
2000: push is 36% faster
20000: push is 50% faster
200000: push is dead, maximum call stack exceeded

.push is becoming faster starting from 60 elements in the second array
.concat is becoming faster starting from 50 elements in the second array

so, for small arrays <60 elements and also for super huge arrays the loop is better

i doubt that speed should be the driving factor of +++, the main point (feature) is the mutation, right

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants