v icon indicating copy to clipboard operation
v copied to clipboard

Mutability breaks encapsulation principle

Open gchumillas opened this issue 8 months ago • 2 comments

Describe the bug

Do not expose internal implementation details to the end-user of a library. Follow discussion here: https://github.com/vlang/v/discussions/24718

Reproduction Steps

Write a small library:

module my_library

pub struct MyStruct {
mut:
    // the variable 'aaa' is not accessible outside the library
    aaa bool
pub:
    bbb string
}

// the 'aaa' function changes a property that is inaccessible outside the library
fn (mut u MyStruct) aaa() {
    u.aaa = false
}

pub fn (mut u MyStruct) bbb() {
    u.aaa()
}

and use it from a small app:

import my_library

fn main() {
	// the user is forced to declare the variable 'a' as mutable
	// although they don't understand why, since apparently no visible property changes
	mut a := my_library.MyStruct{}
	a.bbb()
}

Expected Behavior

The user should not be forced to mark a as mutable, since from their perspective the bbb method doesn't mutate any public property.

Current Behavior

The compiler forces the end-user to mark a as mutable.

Possible Solution

I think we should distinguish between "private" | "public" and "visible" properties. For someone working in the library, the property aaa is "private" and "visible." And from the end user's perspective, aaa is "not visible." Therefore, the reasoning would be:

If "the function changes some properties visible to the user" {
    "mut" is required
}

Is that possible? No idea :)

Additional Information/Context

No response

V version

V 0.4.10 36bef92

Environment details (OS name and version, etc.)

V full version V 0.4.10 36bef926fb9642378f6514886af7ce16279357f5
OS macos, macOS, 15.5, 24F74
Processor 8 cpus, 64bit, little endian, Apple M1 Pro
Memory 0.31GB/16GB
V executable /Users/gonzalo/Projects/Personal/vlang/v/v
V last modified time 2025-06-13 16:56:30
V home dir OK, value: /Users/gonzalo/Projects/Personal/vlang/v
VMODULES OK, value: /Users/gonzalo/.vmodules
VTMP OK, value: /tmp/v_501
Current working dir OK, value: /Users/gonzalo/Projects/Personal/vlang/v
Git version git version 2.39.1
V git status weekly.2025.24-12-g36bef926
.git/config present true
cc version Apple clang version 17.0.0 (clang-1700.0.13.5)
gcc version Apple clang version 17.0.0 (clang-1700.0.13.5)
clang version Apple clang version 17.0.0 (clang-1700.0.13.5)
tcc version tcc version 0.9.28rc 2024-02-05 HEAD@105d70f7 (AArch64 Darwin)
tcc git status thirdparty-macos-arm64 e447816c
emcc version N/A
glibc version N/A

[!NOTE] You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote. Other reactions and those to comments will not be taken into account.

gchumillas avatar Jun 14 '25 11:06 gchumillas

Connected to Huly®: V_0.6-23070

huly-for-github[bot] avatar Jun 14 '25 11:06 huly-for-github[bot]

One alternative is use a factory function new_my_struct_bbb() doing the mut internally and returning a never mut again object:

pub struct MyStruct {
mut:
    aaa bool
pub:
    bbb string
}

fn (mut u MyStruct) aaa() {
    u.aaa = false
}

pub fn new_my_struct_bbb() MyStruct {
	mut m := MyStruct{}
	m.aaa()
	return m
}

fn main() {
	m := new_my_struct_bbb()
	println(m)
}

jorgeluismireles avatar Jun 14 '25 13:06 jorgeluismireles