Skip to content

[Stdlib] Add capitalize() and title() to String and StringSlice#6169

Draft
msaelices wants to merge 6 commits intomodular:mainfrom
msaelices:feat/string-title-capitalize
Draft

[Stdlib] Add capitalize() and title() to String and StringSlice#6169
msaelices wants to merge 6 commits intomodular:mainfrom
msaelices:feat/string-title-capitalize

Conversation

@msaelices
Copy link
Contributor

@msaelices msaelices commented Mar 14, 2026

Adds Python-compatible capitalize() and title() string methods to StringSlice (implementation) and String (delegating wrappers).

  • capitalize(): first character uppercased, rest lowercased.
  • title(): each word's first character uppercased, rest lowercased. Word boundaries are non-alphabetic characters, matching Python's str.title() semantics.

Both methods process ASCII characters only; non-ASCII bytes are passed through unchanged.


Tracking issue: #6177. Keeping as draft until consensus is reached there.


Assisted-by: AI

ArcPointer already implements Identifiable (pointer-identity semantics via
__is__/__isnot__). Adding __hash__ based on the inner pointer address
makes the identity relation consistent with hashing — two ArcPointers that
point to the same allocation always produce the same hash, enabling use
as Dict/Set keys.

Signed-off-by: Manuel Saelices <[email protected]>
Adds Python-compatible `capitalize()` and `title()` string methods to
`StringSlice` (implementation) and `String` (delegating wrappers).

- `capitalize()`: returns a copy with the first character uppercased
  and the rest lowercased.
- `title()`: returns a copy where each word's first character is
  uppercased and the rest are lowercased. Word boundaries are
  non-alphabetic characters, matching Python's `str.title()` semantics.

Both methods are ASCII-only; non-ASCII bytes pass through unchanged.

Signed-off-by: Manuel Saelices <[email protected]>
@msaelices msaelices requested a review from a team as a code owner March 14, 2026 21:41
Copilot AI review requested due to automatic review settings March 14, 2026 21:41
@github-actions github-actions bot added mojo-stdlib Tag for issues related to standard library waiting-on-review mojo-docs labels Mar 14, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the stdlib with Python-like string casing helpers (capitalize() / title()) on StringSlice (core implementation) and String (delegating wrappers), and also adds pointer-identity Equatable/Hashable support for ArcPointer with accompanying tests and changelog notes.

Changes:

  • Add StringSlice.capitalize() and StringSlice.title() plus String wrapper methods.
  • Make ArcPointer conform to Equatable and Hashable (hashing by pointer identity) and add unit tests for equality/hash behavior.
  • Update nightly changelog with ArcPointer hashability note.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
mojo/stdlib/std/collections/string/string_slice.mojo Implements capitalize() and title() logic on StringSlice.
mojo/stdlib/std/collections/string/string.mojo Adds String wrappers delegating to StringSlice.
mojo/stdlib/test/collections/string/test_string_slice.mojo Adds tests for new StringSlice casing APIs.
mojo/stdlib/test/collections/string/test_string.mojo Adds tests for String casing wrappers.
mojo/stdlib/std/memory/arc_pointer.mojo Adds Equatable/Hashable conformance and pointer-identity hash/eq.
mojo/stdlib/test/memory/test_arc.mojo Adds tests for ArcPointer hashing and equality.
mojo/docs/nightly-changelog.md Documents new ArcPointer Hashable behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +130 to +136
# A distinct allocation is a different pointer: its address differs, so its
# hash value differs (hash is the raw address, so no collision is possible
# for two simultaneously live allocations).
var r = ArcPointer(42)
assert_true(hash(p) != hash(r))


Comment on lines +2298 to +2309
def capitalize(self) -> String:
"""Returns a copy of the string with the first character uppercased and the rest lowercased.

Processes ASCII characters only. Non-ASCII characters are passed through unchanged.

Returns:
A new `String` with the first character uppercased and the remaining characters lowercased.
"""
if self.byte_length() == 0:
return String("")
var result = self.lower()
var ptr = result.unsafe_ptr_mut()
Comment on lines +2338 to +2339
elif b >= ord("A") and b <= ord("Z"):
prev_cased = True
Comment on lines +1179 to +1211
def test_capitalize() raises:
# Basic
assert_equal(StringSlice("hello world").capitalize(), "Hello world")
# All upper
assert_equal(StringSlice("HELLO").capitalize(), "Hello")
# Mixed
assert_equal(StringSlice("hELLO").capitalize(), "Hello")
# Empty
assert_equal(StringSlice("").capitalize(), "")
# Non-alpha first char
assert_equal(StringSlice("123abc").capitalize(), "123abc")
# Single char
assert_equal(StringSlice("a").capitalize(), "A")


def test_title() raises:
# Basic
assert_equal(StringSlice("hello world").title(), "Hello World")
# Already title case
assert_equal(StringSlice("Hello World").title(), "Hello World")
# All caps
assert_equal(StringSlice("HELLO WORLD").title(), "Hello World")
# Empty
assert_equal(StringSlice("").title(), "")
# Hyphenated
assert_equal(StringSlice("hello-world").title(), "Hello-World")
# Apostrophe (Python behavior: apostrophe is non-alpha, so char after it is uppercased)
assert_equal(StringSlice("it's a test").title(), "It'S A Test")
# Digits
assert_equal(StringSlice("123abc def").title(), "123Abc Def")
# Single word
assert_equal(StringSlice("hello").title(), "Hello")

Comment on lines +61 to +64
- `ArcPointer` now conforms to the `Hashable` trait, enabling its use as a
`Dict` key or `Set` element. The hash is based on the allocation address,
consistent with pointer-identity semantics (`a is b` implies
`hash(a) == hash(b)`).
Comment on lines +61 to +64
- `ArcPointer` now conforms to the `Hashable` trait, enabling its use as a
`Dict` key or `Set` element. The hash is based on the allocation address,
consistent with pointer-identity semantics (`a is b` implies
`hash(a) == hash(b)`).
@NathanSWard
Copy link
Contributor

Please see here: #6168 (comment)

@msaelices
Copy link
Contributor Author

msaelices commented Mar 15, 2026

Opened issue #6177 to track the justification for this API as requested. In the meantime, converted PR to draft.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mojo-docs mojo-stdlib Tag for issues related to standard library waiting-on-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants