Appendix IV - The Psychological Transition From C To Rust

The transition from C to Rust is often described as a technical transition: from manual memory management to a language in which memory safety is enforced by the type system. From a psychological perspective, however, something more interesting is happening.

The programmer is not simply learning a new set of rules. The programmer is being asked to represent the program differently.

The central proposition of this appendix is:

The stronger the memory-safety constraints imposed by a programming language, the more the programmer must construct a mental model in which ownership, aliasing, mutation, and lifetime are explicit properties of the program.

This does not mean that memory-safe programming necessarily requires more thinking. Rather, it changes what the programmer must think about, when that thinking occurs, and which aspects of the program become cognitively salient.

Mental Models and Programming

Programming is fundamentally a cognitive activity. A programmer cannot manipulate an entire program directly; instead, the programmer constructs an internal representation of the program and reasons through that representation.

Research on programming has explicitly examined these internal representations as "mental models." Canas, Bajo, and Gonzalvo (1994), for example, demonstrated that different forms of programming instruction can produce differences in how programmers represent programming concepts. More broadly, research into programming expertise suggests that experienced programmers develop increasingly structured representations that allow them to recognize meaningful patterns without reasoning about every detail independently.

This distinction is important. A programmer can sometimes produce correct code without possessing the same conceptual representation as another programmer.

The question, therefore, is not merely whether a programmer can use Rust successfully. It is what the programmer has learned to regard as important when thinking about a Rust program.

In C, a programmer may be able to reason about a data structure principally in terms of values, addresses, pointers, and operations. In Rust, the same programmer must increasingly reason in terms of ownership, borrowing, mutability, movement, and lifetime.

The language has changed the problem representation.

The C Mental Model

C permits a relatively direct conceptual model of memory.

An object exists somewhere in memory. A pointer identifies an address. Code follows the pointer and performs an operation on the object.

Of course, experienced C programmers know that this model is incomplete. They understand allocation, deallocation, ownership conventions, aliasing rules, lifetime requirements, and the dangers of undefined behaviour.

The important point is that C does not require most of this knowledge to be represented explicitly in the language's type system.

A programmer can therefore maintain many important invariants informally.

For example:

this pointer belongs to this subsystem
this object must remain alive until this function returns
this function may mutate the object
this other function must not mutate it simultaneously
this allocation must eventually be freed

These facts may exist entirely in the programmer's head, in documentation, in naming conventions, or in the social conventions of a programming team.

C allows the programmer considerable freedom to decide how much of this structure to make explicit.

That freedom is powerful.

It is also cognitively consequential.

Rust Makes Relationships Explicit

Rust changes the situation.

The programmer is no longer concerned only with what a value is and what operation should be performed upon it. The programmer must also express important relationships between values.

Who owns this value?

Who may access it?

Is access shared or exclusive?

May the access modify the value?

How long may the reference remain valid?

What happens to the original binding after the value is moved?

These questions introduce concepts that are comparatively easy to leave implicit in C.

Psychologically, this matters because the programmer's attention is being redirected.

The programmer moves from thinking primarily about objects and operations toward thinking about relationships between objects.

A simplified contrast is:

C:
object -> address -> operation

Rust:
value -> owner -> permitted access -> lifetime

The second model is more relational.

The programmer must reason not only about the object, but about the rights and temporal conditions surrounding the object.

From Memory To Authority

This suggests that "memory safety" may be an incomplete description of the psychological transition.

Rust does not merely ask:

Where is this object?

It increasingly asks:

Who has authority over this object?

Ownership is a form of authority.

A mutable reference represents a particular form of authority.

A shared reference represents a more restricted form of authority.

A lifetime describes the temporal extent over which a particular relationship remains valid.

Seen this way, Rust encourages the programmer to conceptualize memory not simply as storage, but as a system of permissions and relationships.

This is a significant conceptual shift.

The programmer's vocabulary changes from:

address
pointer
allocation
deallocation
mutation

toward:

ownership
borrowing
shared access
exclusive access
movement
lifetime

These are not merely additional technical terms. They constitute a different way of representing computational state.

Constraints Redistribute Cognitive Work

It is tempting to say that Rust simply imposes additional cognitive load.

There is evidence that it does impose a real learning cost. Coblenz, Mazurek, and Hicks (2022) conducted a randomized controlled study involving 428 students and compared standard Rust with a version incorporating garbage collection. On a task involving complex aliasing, participants using garbage collection were more likely to finish within the available time, and successful participants completed the task substantially faster. Participants also identified ownership, borrowing, and lifetimes as major sources of difficulty.

This provides unusually direct evidence that Rust's memory-management model creates genuine cognitive demands.

But "more cognitive load" is not quite the whole story.

A better description is:

Rust redistributes cognitive work.

Consider a memory error in C.

A programmer may:

1. write the program;
2. compile successfully;
3. execute it;
4. encounter a failure;
5. reconstruct the relevant ownership and lifetime relationships;
6. diagnose the problem.

Rust moves some of that reasoning earlier:

1. design the relationships;
2. express them in the program;
3. receive static feedback;
4. revise the design;
5. compile.

The intellectual work has not necessarily disappeared.

Some of it has moved from debugging to design.

This distinction is psychologically significant.

C permits the programmer to postpone certain forms of reasoning.

Rust makes more of them unavoidable during construction.

Why The Borrow Checker Feels Like An Obstacle

This helps explain a characteristic experience reported by many programmers learning Rust: the feeling of "fighting the borrow checker."

The programmer arrives with an existing mental model.

That model may have been developed through C, C++, Java, or another language. When the programmer writes Rust, they naturally attempt to project the existing model onto the new language.

The compiler then rejects the program.

From the programmer's perspective, the experience can initially be:

"I know what I want to do. Why will the language not let me?"

This is a conceptual mismatch.

The programmer's existing representation says that the operation is reasonable.

Rust's semantic model says that some relationship required by the operation has not been established.

Research specifically on Rust learners supports this interpretation. Crichton, Gray, and Krishnamurthi (2023) found that learners had difficulty connecting Rust's static rules with the dynamic behaviour those rules are intended to prevent. Their work also developed a permissions-based conceptual model to make ownership and borrowing easier to understand.

The psychological transition can therefore be described in three stages.

FIRST: Resistance

"The compiler is preventing me from doing something reasonable."

The programmer's old mental model remains primary.

SECOND: Translation

"I understand that Rust wants me to express this as an ownership
or borrowing relationship."

The programmer begins to construct a second model.

THIRD: Internalization

"Before I write this function, I already think about who should
own this data."

The Rust model has become part of the programmer's spontaneous reasoning.

This final stage is particularly important.

Expertise does not simply mean remembering more rules. Experts develop organized knowledge structures that allow them to recognize important patterns without reconstructing every detail consciously.

The experienced Rust programmer does not necessarily experience ownership as an additional burden on every line of code.

Ownership has become part of the programmer's intuition.

The Compiler as a Cognitive Instrument

This leads to another interesting consequence.

The compiler is not merely a machine that accepts or rejects programs.

It becomes part of the programmer's reasoning environment.

A Rust error message can expose a relationship that the programmer has failed to represent correctly.

For example, an error concerning mutable and immutable borrowing can be interpreted at two levels.

At the superficial level:

"The compiler will not let me compile this."

At the conceptual level:

"My design requires two incompatible forms of access to the same
state at the same time."

The second interpretation is more powerful.

The compiler has made a property of the programmer's design visible.

This is consistent with research on Rust education. Almeida et al. (2022) developed RustViz, a visualization system that makes ownership and borrowing events visible in ways that otherwise have to be tracked mentally. In their educational deployment, the visualizations were reported to help students develop an accurate mental model of ownership and borrowing.

The significance is broader than RustViz itself.

If a tool can improve learning by making ownership relationships visible, then ownership is not simply a syntactic rule. It is a structure that the learner must mentally represent.

The compiler and associated tools can therefore function as cognitive instruments: they expose relationships that the programmer is learning to perceive.

Constraints Can Reduce the Search Space

Constraints are not inherently harmful to cognition.

A constraint removes possibilities.

Removing possibilities can increase the amount of reasoning required in one respect while reducing it in another.

Suppose a programmer is reasoning about shared mutable state.

In an unconstrained environment, the programmer may have to consider a large space of possible interactions and potential failures.

A sufficiently strong type system eliminates some of those possibilities before execution.

The programmer can therefore reason within a smaller space.

This produces a paradox:

Stronger constraints can increase local cognitive effort while reducing the global space of possibilities.

The programmer may spend more time deciding how ownership should work, but less time reasoning about entire classes of possible memory failures.

This is one reason that the learning experience and the experienced-user experience can be very different.

For the novice, the constraint is an obstacle.

For the expert, the same constraint can function as a cognitive scaffold.

From Informal Invariants to Enforced Invariants

The deepest change may therefore concern where program invariants reside.

In C, an invariant such as:

"This pointer must never outlive the object to which it points"

may exist primarily as programmer knowledge.

In Rust, the programmer attempts to encode the relevant relationship in the type and ownership structure so that the compiler can enforce it.

This changes the relationship between programmer and language.

C effectively says:

"You are responsible for maintaining this invariant."

Rust increasingly says:

"Express this invariant in a form that I can check."

This is not merely a technical distinction.

It changes the division of cognitive labour between human and tool.

The programmer must understand the invariant well enough to design the program.

The compiler then assumes responsibility for checking a substantial part of it.

In this sense, a type system can be understood as an externalized part of the programmer's reasoning process.

Rather than remembering every possible violation, the programmer can rely on the language to reject certain classes of invalid state.

The cost is that the programmer must learn the language's conceptual model well enough to express the desired invariants.

The Cost of Explicitness

There is, however, a danger in describing this transformation as unambiguously positive.

Explicitness has a cost.

Every concept that becomes visible is another concept that the programmer may have to attend to.

A novice Rust programmer may simultaneously need to track:

ownership
borrowing
mutability
lifetimes
moves
references
type inference
trait constraints

This can exceed the programmer's available working memory.

Cognitive Load Theory, developed by Sweller and colleagues, predicts that learning becomes difficult when learners must coordinate too many interacting elements simultaneously.

Rust can therefore feel disproportionately difficult during the early stages of learning.

The critical point is that some of this difficulty may be intrinsic to the underlying problem rather than caused entirely by Rust.

Memory-safe systems programming really does contain complicated relationships.

C allows some of those relationships to remain implicit.

Rust makes more of them visible.

The language therefore exposes complexity that might otherwise remain hidden until debugging.

The Crucial Distinction: Learning Rules vs Learning a Model

There is an important qualification.

A programmer can learn to satisfy the borrow checker without developing a deep understanding of ownership.

This would represent rule acquisition rather than conceptual change.

For example, a programmer might learn:

"Adding this clone makes the compiler happy."

without understanding why cloning changes the ownership relationship.

Such knowledge can produce working code while leaving the underlying mental model largely unchanged.

The stronger form of learning occurs when the programmer begins to anticipate the constraints.

Instead of:

write code -> compiler complains -> repair code

the experienced programmer increasingly operates as:

imagine ownership structure -> design API -> write code

The compiler is no longer merely correcting the programmer.

The programmer has incorporated the compiler's model into the design process.

This is the point at which a constraint becomes internalized.

The Transition from C to Rust as a Change in Ontology

This may be the most useful way to understand the transition.

The difference is not simply:

C + safety rules = Rust

The deeper difference is:

C and Rust encourage somewhat different ways of representing program state.

In one mental model, memory is primarily something the programmer manipulates.

In the other, memory is something over which the program establishes relationships of ownership, access, and temporal validity.

The programmer has therefore acquired a different ontology of state.

This is why learning Rust can sometimes feel strangely profound to experienced C programmers.

They are not simply learning syntax.

They are learning to notice things that previously existed mostly in the background.

They begin to see questions such as:

Who owns this?

Who is allowed to mutate it?

How long must it remain valid?

Can these two operations coexist?

Should this function consume the value or borrow it?

Is this relationship structural or temporary?

These questions become part of the programmer's perception of the problem itself.

A Revised Form of the Original Claim

The original proposition can now be stated more precisely:

The stronger the memory-safety constraints imposed by a programming language, the more the programmer is encouraged, and in some cases required, to construct a mental model in which ownership, access, mutation, and lifetime are explicit features of the program.

But there is an important qualification:

Stronger constraints do not automatically produce better mental models. They create pressure for a different mental model to develop.

Whether that model develops depends on education, experience, tooling, and the programmer's ability to connect the language's static rules with the underlying computational concepts.

This distinction matters.

A programmer who learns Rust as a collection of compiler-appeasement techniques has learned the rules.

A programmer who begins designing data structures by asking who owns the data has changed their mental model.

Conclusion

The psychological significance of memory safety is therefore deeper than the prevention of memory errors.

Memory safety changes the questions that programmers habitually ask.

C permits the programmer to reason about memory relationships largely through informal knowledge.

Rust makes many of those relationships part of the formal structure of the program.

The immediate result can be increased cognitive load. Empirical research on Rust confirms that ownership, borrowing, and lifetimes create substantial difficulties for learners.

But the longer-term result can be a transformation in expertise.

What initially appears as an external restriction can become an internalized way of thinking.

The programmer stops asking:

"How do I make the compiler accept this?"

and begins asking:

"What ownership relationship does this design actually require?"

That is the deeper psychological transition from C to Rust.

The language has not merely changed what the programmer is permitted to write.

It has changed what the programmer is trained to notice.

And perhaps this is the most consequential property of a programming language:

A language does not merely provide a vocabulary for expressing thoughts about computation.

It helps determine which thoughts come naturally in the first place.

References

Almeida, M., Cole, G., Ke, D., Luo, G., Pan, S., Pan, Y., Qiu, K., Reddy, V., Zhang, H., & Zhu, Y. (2022). RustViz: Interactively Visualizing Ownership and Borrowing. IEEE Symposium on Visual Languages and Human-Centric Computing (VL/HCC). https://doi.org/10.1109/VL/HCC53370.2022.9833121

Canas, J. J., Bajo, M. T., & Gonzalvo, P. (1994). Mental models and computer programming. International Journal of Human-Computer Studies, 40(5), 795-811. https://doi.org/10.1006/ijhc.1994.1038

Coblenz, M., Mazurek, M., & Hicks, M. (2022). Garbage Collection Makes Rust Easier to Use: A Randomized Controlled Trial of the Bronze Garbage Collector. Proceedings of the 44th International Conference on Software Engineering (ICSE), 1021-1032. https://doi.org/10.1145/3510003.3510107

Crichton, W., Gray, G., & Krishnamurthi, S. (2023). A Grounded Conceptual Model for Ownership Types in Rust. arXiv:2309.04134. https://arxiv.org/abs/2309.04134

Green, T. R. G., & Petre, M. (1996). Usability analysis of visual programming environments: A "cognitive dimensions" framework. Journal of Visual Languages & Computing, 7(2), 131-174. https://doi.org/10.1006/jvlc.1996.0009

Pennington, N. (1987). Stimulus structures and mental representations in expert comprehension of computer programs. Cognitive Psychology, 19(3), 295-341. https://doi.org/10.1016/0010-0285(87)90007-7

Sweller, J. (1988). Cognitive load during problem solving: Effects on learning. Cognitive Science, 12(2), 257-285. https://doi.org/10.1207/s15516709cog1202_4

Wiedenbeck, S., Fix, V., & Scholtz, J. (1993). Characteristics of the mental representations of novice and expert programmers: An empirical study. International Journal of Man-Machine Studies, 39(5), 793-812. https://doi.org/10.1006/imms.1993.1084

Note On Evidence

The strongest direct empirical evidence for the specific cognitive difficulty of Rust's ownership model is Coblenz, Mazurek, and Hicks (2022), which used a randomized controlled study to compare Rust with an alternative incorporating garbage collection.

Almeida et al. (2022) provide complementary evidence that making ownership and borrowing relationships visually explicit can help learners construct an accurate mental model.

Crichton, Gray, and Krishnamurthi (2023) provide further evidence that learners have difficulty connecting Rust's static ownership rules with the dynamic behaviour those rules are intended to prevent.

The remaining references provide broader psychological foundations concerning mental models, cognitive load, programming expertise, and the cognitive dimensions of programming languages.


← Previous Bibliography →