Skip to content

builtin: add arr.pop_left() func#25133

Merged
spytheman merged 6 commits into
vlang:masterfrom
kbkpbot:builtin-array-shift
Aug 19, 2025
Merged

builtin: add arr.pop_left() func#25133
spytheman merged 6 commits into
vlang:masterfrom
kbkpbot:builtin-array-shift

Conversation

@kbkpbot

@kbkpbot kbkpbot commented Aug 18, 2025

Copy link
Copy Markdown
Contributor

Feature require by #24591

Just like array.pop(), array.pop_left() act like ret=array.first() array.delete(0)

@huly-for-github

Copy link
Copy Markdown

Connected to Huly®: V_0.6-23654

@JalonSolov

Copy link
Copy Markdown
Collaborator

So... same as arr.delete(0), correct?

@kbkpbot

kbkpbot commented Aug 18, 2025

Copy link
Copy Markdown
Contributor Author

So... same as arr.delete(0), correct?

Not exactly.
It returns the first element, and then delete(0)...

@JalonSolov

Copy link
Copy Markdown
Collaborator

Ah, alright.

Comment thread vlib/builtin/array.v
Comment thread vlib/builtin/array_d_gcboehm_opt.v
@spytheman

Copy link
Copy Markdown
Contributor

I am curious, why is it called .shift() here, and not .pop_left() as in the issue?

@kbkpbot

kbkpbot commented Aug 18, 2025

Copy link
Copy Markdown
Contributor Author

I am curious, why is it called .shift() here, and not .pop_left() as in the issue?

which name is best?
shift, pop_left, pop_front, remove_first, dequeue.... ? :)

I vote for shift, as JS and shell have the same shift func.

@spytheman

Copy link
Copy Markdown
Contributor

I have no opinion on the name. If there is an existing precedent for .shift(), fine.

Comment thread vlib/builtin/array_d_gcboehm_opt.v Outdated
@kbkpbot

kbkpbot commented Aug 18, 2025

Copy link
Copy Markdown
Contributor Author
// free frees all memory occupied by the array.
@[unsafe]
pub fn (a &array) free() {
	$if prealloc {
		return
	}
	// if a.is_slice {
	// return
	// }
	if a.flags.has(.nofree) {
		return
	}
	mblock_ptr := &u8(u64(a.data) - u64(a.offset))
	if mblock_ptr != unsafe { nil } {
		unsafe { free(mblock_ptr) }
	}
	unsafe {
		a.data = nil
		a.offset = 0
	}
}

Is the free() implement here correct? If we use shift and then update the .offset, the mblock_ptr will point to a wrong address.

@spytheman

Copy link
Copy Markdown
Contributor

No one updates .offset except the .slice method (for creating a new slice view) and now the .shift one (which in essence also creates a new slice + returning the first element of the old).
-> the free method is correct.

@kbkpbot

kbkpbot commented Aug 18, 2025

Copy link
Copy Markdown
Contributor Author

No one updates .offset except the .slice method (for creating a new slice view) and now the .shift one (which in essence also creates a new slice + returning the first element of the old). -> the free method is correct.

Yes, you are right.

@spytheman

Copy link
Copy Markdown
Contributor

(i.e. the purpose of the .offset field, is that in combination with .data, you can always get back to the original memory block start, even when creating multiple slices/views to the same elements)

@JalonSolov

Copy link
Copy Markdown
Collaborator

So...

LangFunction
JavaScriptshift()
C++erase(offset)
Javaremove(offset)
Pythondel arr[offset]
C#RemoveAt(offset)

Basically, there is no "standard" way of doing this.

@kbkpbot

kbkpbot commented Aug 18, 2025

Copy link
Copy Markdown
Contributor Author

So...

Lang Function
JavaScript shift()
C++ erase(offset)
Java remove(offset)
Python del arr[offset]
C# RemoveAt(offset)
Basically, there is no "standard" way of doing this.

Lang Function
JavaScript shift()
C++ erase(offset),std::deque.pop_front()
Java remove(offset)
Python del arr[offset], pop(0), popleft()
C# RemoveAt(offset)
PHP array_shift()
Ruby shift
Perl shift @array
Rust VecDeque.pop_front()
Swift removeFirst()

@blackshirt

blackshirt commented Aug 19, 2025

Copy link
Copy Markdown
Contributor

shift sounds like the brother of left_shift and right_shift for me

@spytheman

spytheman commented Aug 19, 2025

Copy link
Copy Markdown
Contributor

I think that pop_front or pop_left may be more descriptive and less confusing (but I am fine with shift too).
The erase/deletes that use an offset tend to not return the element, so they are not direct analogs/models for this.
@medvednikov what do you think?

@JalonSolov

Copy link
Copy Markdown
Collaborator

To me, shift, left_shift, and right_shift don't make sense. You're not shifting anything. An array makes more sense as a stack (think of a stack of plates), so you would push things onto the stack, and pop them off.

Of course, then you run into... push where? Onto the top of the stack or the bottom? Etc., etc.

At any rate, as long as it's documented, it doesn't matter that much. It's more a cognitive thing... what would make the most sense if you didn't know what was there, and you were searching for it?

Last... it seems like it wouldn't hurt anything to just make arr.delete(offset) return the value that was deleted. No new routines to be added, and no breaking changes to the code.

@spytheman

Copy link
Copy Markdown
Contributor

no, delete has a different semantic (and implementation) compared to this method

@spytheman

spytheman commented Aug 19, 2025

Copy link
Copy Markdown
Contributor

You're not shifting anything.

yes, you are shifting the start of the array, mut a:=[10,20,30]; a.shift(); println(a) will print [20,30] after this method is called.

@spytheman

spytheman commented Aug 19, 2025

Copy link
Copy Markdown
Contributor

An array makes more sense as a stack

The intention is that this method can be used in the implementation of a queue (avoiding the copying/movement that delete(x) does).

@spytheman

Copy link
Copy Markdown
Contributor

At any rate, as long as it's documented, it doesn't matter that much. It's more a cognitive thing... what would make the most sense if you didn't know what was there, and you were searching for it?

I agree that documentation can help with clearing the meaning and behavior. The name decision at this point boils down to a balance between mnemonics and clarity.

@spytheman

spytheman commented Aug 19, 2025

Copy link
Copy Markdown
Contributor

I tend to prefer .pop_left() the more I think about it, because we already do have .pop(), and we already do have several other _left() suffixed methods in builtin.

i.e. my preference is currently in this order:

  1. pop_left() or shift()
  2. pop_front()

@blackshirt

Copy link
Copy Markdown
Contributor

pop_left() feel the good names ...its describes well on its own

@kbkpbot

kbkpbot commented Aug 19, 2025

Copy link
Copy Markdown
Contributor Author

OK, I will change shift to pop_left.

@kbkpbot kbkpbot changed the title builtin: add arr.shift() func builtin: add arr.pop_left() func Aug 19, 2025

@spytheman spytheman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work @kbkpbot .

I've asked @medvednikov on Discord, and he agrees with the pop_left() name too.

@spytheman spytheman merged commit a818744 into vlang:master Aug 19, 2025
83 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants