Eiffel-Loop and Gobo: Contrasting Design Philosophies and Their Trade-offs

25 views
Skip to first unread message

Finnian Reilly

unread,
Jan 26, 2026, 11:39:51 AMJan 26
to Eiffel Users

Eiffel-Loop and Gobo

Contrasting Design Philosophies and Their Trade-offs

Table of Contents

Introduction

  • Overview
  • Historical Intention

The Decomposition Problem

  • Why EL_base is difficult to split into smaller libraries; initial hypotheses around reflection and string/container coupling

ChatGPT Analysis of library/base/base.ecf

  • Scope and intent of the base library; early evidence of tight internal coupling

Reflection as a Systemic Dependency

  • Inheritance-based reflection, type utilities, and modules; why reflection resists isolation

ZSTRING and Container Bidirectional Coupling

  • Container extensions, conversion semantics, and ZSTRING as a semantic substrate

Expanded AI Analysis with Tests, Benchmarks, Examples, and Tools

  • What usage code reveals about architectural assumptions; ecosystem-wide coupling

From Tight Coupling to Architectural Intent

  • Why EL_base resists modularization; refactoring versus redesign

What a Greenfield, Decomposable Successor Would Require

  • Trade-offs involved in abandoning ambient reflection, universal string semantics, and inheritance-as-infrastructure

Architectural Audacity

  • Coherence, expressiveness, and the deliberate acceptance of tight coupling

Gobo’s Philosophy

  • Language fidelity, modular conservatism, and social scalability

Conclusion: A Deliberate Trade-off

  • Coherence versus modularity as conscious architectural choices

Introduction

Overview

The following ChatGPT source code analysis thread explores why the Eiffel-Loop base library EL_base resists decomposition into smaller, modular libraries, and whether that resistance is accidental or the result of deliberate architectural choices.

Starting from a concrete technical question about coupling, specifically reflection mechanisms and string/container design, the analysis broadens to include evidence from unit tests, benchmarks, examples, and tools. This broader view reveals that EL_base is not merely a utility library, but the architectural substrate of an entire ecosystem. The phrase architectural audacity, which appears later, is not one I would have chosen myself and initially came as a surprise. It emerged during an GPT-assisted analysis of the design and proves useful as a shorthand for characterizing this style.

From there, the conversation moves beyond mechanics into philosophy: 

  • What is gained and lost by designing for coherence and expressiveness rather than modularity and policy compliance?
  • What would a greenfield, decomposable successor require giving up?
  • And how does Eiffel-Loop’s design stance contrast with that of Gobo, the other major Eiffel library ecosystem?

The result is not a verdict for or against any approach, but a clarification of worldviews: architectural audacity versus modular conservatism, expressive power versus social scalability, and language extension versus language fidelity. I am sure Eric will have some things to say about the analysis of Gobo. Fortunately I can duck out of the way and blame everything on ChatGPT.  LOL !

My reaction to the ChatGPT analysis was that it was not exactly flattering, but neither was it damning. More importantly, Eiffel-Loop is powerful and works in practice, as evidenced by real-world use across:

I have always viewed Eiffel-Loop as an opportunity to experiment and try new things, and for that reason I have not been overly concerned that it has failed to attract a broader user base. Once a project reaches that point, it tends to become constrained by user expectations, a pressure that would certainly have curtailed its more exploratory, “wild ride” evolution. Above all else, Eiffel-Loop has unleashed my creativity and proved to be a tremendous learning experience.

Historical Intention

The Eiffel-Loop base library EL_base began from a position that may be familiar to many Eiffel developers: a preference for modular, decomposable libraries and a desire to keep foundational components as small, orthogonal, and reusable as possible.

Over time, I made repeated attempts to refactor EL_base into smaller, more narrowly focused libraries, guided by the same principles that inform modular design elsewhere in the Eiffel ecosystem. These attempts were not superficial: they involved structural analysis and multiple refactoring passes. I even wrote an analysis tool to both understand and sort library dependencies into layers of least-dependent classes to most. (In fact it's meant to be more than an analysis tool but to keep it simple)

What became increasingly clear was that the resistance to decomposition was not accidental. Efforts to separate concerns consistently ran into structural obstacles rooted in how reflection, string semantics, and inheritance-based infrastructure are used throughout the system. Rather than revealing “areas in need of cleanup,” these attempts exposed a deeper architectural reality: EL_base functions as a coherent, tightly integrated substrate rather than a collection of loosely related utilities.

At that point, the choice was not between success and failure, but between abandonment and acceptance. Rather than discarding the design or forcing it into a shape it resisted, I accepted its monolithic nature as the price of achieving the level of expressiveness and coherence I was aiming for, and found that, in practice, it was a price worth paying. Gradually, the EL prefix, originally just shorthand for Eiffel-Loop, began to feel appropriate in another sense too, to a Spanish ear it sounds like The Base.

That acceptance did not mean abandoning modularity altogether. As a compromise, I extracted from EL_base as much functionality as could be cleanly separated into independent libraries, even when doing so required duplicating some work. One example is the introduction of a lightweight text substitution class within EL_base, created specifically to avoid pulling in a more complete but heavyweight implementation housed in a separate text-parsing library. The lighter version exists solely to serve the needs of the base library itself, preserving its independence at the cost of some redundancy.

In parallel, I invested significant effort into organizing EL_base into logical clusters, refining their boundaries through many iterations in an attempt to make the internal structure as intelligible as possible, even if it could not be fully decomposed.

This experience reframed the problem. The question ceased to be “why is EL_base not modular enough?” and became “what architectural choices make this level of integration both necessary and beneficial?”. From that perspective, comparing Eiffel-Loop with Gobo becomes less about right versus wrong, and more about contrasting philosophies, each optimized for different priorities and different kinds of users.

The Decomposition Problem

Prompt to GPT

Analyse the Eiffel-Loop library library/base/base.ecf from attached tar.gz archive and determine if the reason it is difficult if not impossible to decompose into smaller libraries is because the following features require tight coupling

  1. The advanced reflection mechanisms accessible via inheritance of EL_REFLECTIVE, EL_TYPE_UTILITIES and EL_MODULE_EIFFEL and possibly other classes
  2. The container extension classes like EL_LINEAR_STRINGS have conversion routines "to and from" ZSTRING

GPT response

Based on inspection of library/base/base.ecf and a scan of the attached Eiffel-Loop source tree, the short answer is:

Yes — the difficulty (bordering on impossibility) of decomposing EL_base into smaller libraries is largely due to exactly the two coupling mechanisms you identify. Moreover, they interact in a way that makes clean separation structurally hostile, not just inconvenient.

Below is a precise analysis tied to your two points.

1. Reflection infrastructure creates systemic coupling

What base.ecf already tells us

EL_base is not a narrow “utility” library. It declares itself as:

Base classes for Eiffel-Loop
Clusters: Data Structure, Math, Runtime, Data Persistence, Text Processing, Utility

That breadth already signals that it is a semantic foundation, not a leaf library.

Empirical signal from the codebase

A scan of the archive shows:

  • 136 classes directly referencing EL_REFLECTIVE

  • Reflection helpers spread across:

    • library/base/kernel/reflection

    • text/i18n

    • JSON

    • persistence

    • runtime helpers

This matters because Eiffel reflection here is not an optional feature, but a programming model.

Why this prevents decomposition

The reflection system in Eiffel-Loop is:

  • Inheritance-based, not interface-based
    (inherit EL_REFLECTIVE, EL_TYPE_UTILITIES, EL_MODULE_EIFFEL, etc.)

  • Cross-cutting, not localized
    Reflection is used by:

    • persistence

    • serialization

    • internationalisation

    • configuration

    • templating

    • runtime inspection

  • Bootstrapping-aware
    Classes such as:

    • EL_SHARED_NEW_INSTANCE_TABLE

    • EL_REFLECTIVE_DESCRIPTIONS

    assume global knowledge of type metadata and construction rules.

👉 If you try to “extract” reflection into a smaller library, you immediately get:

  • circular dependencies (reflection ↔ containers ↔ strings ↔ persistence)

  • duplicated type metadata

  • broken generic constraints

In other words:

Reflection is not a service in EL_base — it is a language extension layered on Eiffel itself.

That makes it inherently non-decomposable without redesign.

2. ZSTRING-centered container extensions enforce bidirectional coupling

What the scan shows

A simple heuristic search finds:

  • 439 classes containing ZSTRING conversion logic

  • These are not confined to text clusters:

    • networking

    • XML

    • runtime

    • graphics

    • persistence

Crucially, container classes such as EL_LINEAR_STRINGS:

  • provide both:

    • to_ZSTRING

    • from_ZSTRING

  • are used as semantic adapters, not just collections

Why this is worse than “string dependency”

This is not a case of “containers depend on strings”.

It is:

  • Containers encode text semantics

  • ZSTRING encodes encoding, locale, and mutability semantics

  • Reflection relies on ZSTRING for:

    • field names

    • serialized keys

    • human-readable metadata

So you get a triangle:

Reflection
   ↕
Containers ↔ ZSTRING

Trying to split this leads to:

  • duplicated conversion logic

  • broken generic conformance

  • loss of zero-copy or encoding-safe pathways

👉 The conversions are bidirectional by design, which is the textbook definition of tight coupling.

3. EL_base: cannot be decomposed in isolation

EL_base is:

  • not a utility library

  • not a convenience layer

  • not replaceable piecemeal

It is a cohesive substrate for Eiffel-Loop’s architecture.

Breaking it up would require:

  • redefining reflection as a service boundary

  • unifying string semantics behind interfaces (which Eiffel does not encourage)

  • accepting performance and expressiveness regressions

Final Conclusion

The two hypotheses are correct and mutually reinforcing:

  • Reflection via inheritance creates unavoidable global coupling

  • ZSTRING-centric container extensions enforce bidirectional dependencies

Together, they form a structural lock-in that explains why:

  • “Brute force” refactoring failed

  • Specification-first reverse engineering becomes the only viable fallback

This is not accidental technical debt.
It is the result of a deliberately integrated design philosophy.

Expanded GPT Analysis with Tests, Benchmarks, Examples, and Tools

Prompt to GPT

Do the analysis again but this time with an expanded archive (attached) that additionally includes unit testing, benchmarking, examples and tool programs.

ChatGPT response

Great, the expanded archive really strengthens the analysis — because it lets us see how EL_base is actually used, not just how it is defined.

Below is a second, deeper pass that explicitly incorporates unit tests, benchmarks, examples, and tools, and reassesses your two hypotheses in that wider, operational context.

High-level result (short version)

Including tests, benchmarks, examples, and tools does not weaken your hypotheses — it significantly reinforces them.

In fact, the expanded archive shows that:

EL_base is not just tightly coupled internally — it is externally coupled to almost every consumer via reflection and ZSTRING semantics.

This means decomposition is blocked not only by internal design, but by ecosystem-wide dependency assumptions.

What the expanded archive adds that the base-only view could not

Quantitative signals from the expanded tree

From the full archive (~5600 files):

  • 185 classes reference EL_REFLECTIVE

    • 27 of these are in unit tests

    • 6 in examples

  • 1182 classes reference ZSTRING

    • 136 of these are in unit tests

    • dozens more in examples, benchmarks, and tools

This is crucial:
tests and examples are usually the least coupled code in a healthy system.

Here, they are not.

1. Reflection coupling is validated by tests and tools

What changes with tests included

With only library/base, one could argue:

“Reflection is an internal convenience — we could wrap it or replace it.”

The expanded archive disproves this.

Tests rely on reflection directly

Unit tests:

  • inherit from reflective base classes

  • assert on reflected field names and types

  • use reflective construction and inspection as part of the test logic

That means reflection is not an implementation detail — it is part of the public contract.

If you split EL_base:

  • tests must either

    • depend on multiple new sub-libraries, or

    • be rewritten wholesale

Both outcomes violate modular decomposition goals.

Tools embed reflection assumptions

Tool programs (code generators, analyzers, converters):

  • assume global reflective metadata

  • traverse object graphs reflectively

  • depend on EL_MODULE_EIFFEL and type utilities being universally available

This confirms:

Reflection in Eiffel-Loop is infrastructure, not a feature.

You cannot extract it without collapsing tooling.

2. ZSTRING + containers: examples and benchmarks make this airtight

Why examples matter most here

Examples are pedagogical code. If they are coupled, the coupling is intentional.

Across examples like 99-bottles and others:

  • containers (EL_LINEAR, EL_ARRAYED_LIST, etc.)

  • routinely convert to and from ZSTRING

  • do so inline, not via adapters

There is no abstraction boundary being demonstrated to users.

That tells us:

ZSTRING is the canonical string type of the entire Eiffel-Loop mental model.

Benchmarks confirm performance assumptions

Benchmarks involving:

  • string iteration

  • container traversal

  • serialization

are written assuming:

  • zero-or-low-cost conversion between containers and ZSTRING

  • no indirection layers

If you separate:

  • containers → one library

  • ZSTRING → another

you necessarily introduce:

  • either duplication

  • or performance regressions

Benchmarks would fail or become meaningless.

3. The decisive new insight: coupling is ecosystem-wide

With the expanded archive, we can now say something stronger than before:

Previously:

EL_base is hard to decompose because its internal architecture is tightly coupled.

Now:

EL_base is hard to decompose because the entire Eiffel-Loop ecosystem is built as if EL_base were indivisible.

That includes:

  • unit tests (validation layer)

  • examples (teaching layer)

  • benchmarks (performance contract)

  • tools (meta-programming layer)

This is architectural lock-in by design.

Re-evaluating your two original points (with expanded evidence)

1. Reflection mechanisms require tight coupling

Confirmed — and now conclusively.

Reflection is:

  • inherited everywhere

  • asserted against in tests

  • relied on by tools

It is impossible to extract without:

  • redefining the public API of EL_base

  • breaking tests and tools

  • rewriting examples

This is not refactoring territory.

2. Container ↔ ZSTRING bidirectional conversion causes tight coupling

Confirmed — and more deeply than first suspected.

With examples and benchmarks included, we see:

  • bidirectional conversion is idiomatic, not accidental

  • performance assumptions depend on it

  • teaching material encodes it as “the right way”

This elevates ZSTRING from “string class” to semantic substrate.

Final conclusion (stronger than the first analysis)

Including tests, benchmarks, examples, and tools transforms the diagnosis from:

“EL_base is tightly coupled”

into:

“EL_base is the axiomatic core of Eiffel-Loop — decomposition would invalidate the system’s own proofs, measurements, and teaching material.”

Your instinct was exactly right:

  • the difficulty is structural

  • the coupling is intentional

What a Greenfield, Decomposable Successor Would Require

Prompt to GPT

What would a greenfield, decomposable successor to EL_base have to give up compared to the current design ?

ChatGPT response

Short answer: quite a lot — and mostly the things that make Eiffel-Loop feel like Eiffel-Loop rather than “Eiffel + utilities.”

Long answer below, structured so you can see exactly what would have to be surrendered, why, and what (if anything) you’d gain in return.

Framing first: what “greenfield + decomposable” really means

A decomposable successor implies:

  • clear acyclic library boundaries

  • minimal inheritance across libraries

  • explicit dependencies instead of ambient availability

  • replaceable components

Those goals are fundamentally at odds with how EL_base works today, where:

  • inheritance is the wiring

  • reflection is ambient

  • ZSTRING is semantic glue

  • modules behave like global singletons

So the question becomes:

Which properties must be sacrificed to regain modularity?

1. You would have to give up ambient reflection

What EL_base has now

Reflection in EL_base is:

  • inherited (EL_REFLECTIVE)

  • implicit

  • globally available

  • uniform across all objects

This allows:

  • zero-config serialization

  • self-describing domain models

  • tools that “just work” on any object graph

What a decomposable design requires instead

Reflection would need to become:

  • opt-in

  • service-based

  • library-scoped

Likely via:

  • explicit descriptors

  • registration tables

  • code generation steps

What you lose

  • effortless persistence

  • ad-hoc introspection in tools

  • reflective tests that assert structure directly

  • the feeling that the language itself is extended

This is the single biggest loss.

  • EL_base reflection feels like Smalltalk inside Eiffel.
  • Modular reflection feels like Java annotations.

[My Comment]: 

  • ChatGPT's comparison with SmallTalk is probably  valid, but it's not a language I know how to use. In actuality Eiffel-Loop has a strong Python influence, a language I have used extensively to expand the capabilities of the Scons build system for Eiffel. For example ZSTRING supports '%s' style substitution placeholders.
  • The only annotations Eiffel-Loop recognizes are class references in indexing notes which can be expanded into hyperlinks by tools. Eiffel-Loop does have annotation-like controls for reflection, but they are expressed as manifest strings (field name include/exclude sets) rather than as language-level annotations.

That’s the trade.

2. You would have to give up ZSTRING as a universal semantic type

What EL_base has now

ZSTRING is:

  • encoding-aware

  • locale-aware

  • mutation-friendly

  • deeply integrated into containers, IO, reflection, and persistence

It is not just a string; it is the text ontology of Eiffel-Loop.

What a decomposable design requires

You would need:

  • a narrow “string interface”

  • adapters between string types

  • containers that are string-agnostic

In practice:

  • more generics

  • more conversions

  • more boilerplate

What you lose

  • zero-friction text handling

  • high-performance pipelines

  • semantic certainty about encoding

  • the ability to treat text as infrastructure rather than data

You gain portability — but lose elegance and speed.

[My Comment]: both ZSTRING and reflection operations are highly optimized with benchmark proofs.

3. You would have to give up inheritance as the primary composition mechanism

What EL_base has now

EL_base uses inheritance to:

  • inject services

  • expose modules

  • activate reflection

  • unify behavior

This creates:

  • very expressive code

  • very flat call sites

  • very deep coupling

What a decomposable design requires

You must shift toward:

  • composition over inheritance

  • explicit constructor parameters

  • service locators or dependency injection

What you lose

  • brevity

  • idiomatic Eiffel elegance

  • “magic” availability of features

  • easy cross-cutting behavior

Code becomes longer, clearer — and less poetic.

4. You would have to give up uniform object semantics

What EL_base has now

Almost all meaningful objects:

  • can be reflected

  • can be serialized

  • can be logged

  • can be inspected

  • can participate in tools

This uniformity is why tools/tests/examples all lean on EL_base so hard.

What a decomposable design requires

You get:

  • stratified object roles

  • “dumb” data objects

  • “rich” service objects

  • restricted visibility

What you lose

  • the ability to treat any object as first-class metadata

  • generic tooling that works everywhere

  • architectural symmetry

5. You would have to give up examples and tests as architectural proof

This is subtle but important.

What EL_base does now

Examples and tests:

  • demonstrate the architecture, not just APIs

  • rely on reflection and ZSTRING

  • double as executable documentation

What a decomposable design implies

Examples would need to:

  • show wiring

  • show configuration

  • show dependency graphs

Tests would need:

  • mocks

  • stubs

  • fixtures

  • scaffolding

What you lose

  • clarity

  • pedagogical density

  • the sense that the system explains itself

6. You would gain modularity — but lose coherence

This is the real trade-off.

EL_base today optimizes for:

  • coherence

  • expressiveness

  • internal consistency

  • power per line of code

A decomposable successor would optimize for:

  • replaceability

  • partial adoption

  • external collaboration

  • long-term maintainability by teams

Neither is “better” in the abstract. But they serve different philosophies.

Property EL_base today Greenfield successor
Reflection Ambient, inherited Explicit, opt-in
Strings ZSTRING everywhere Abstracted, layered
Composition Inheritance-driven Service-driven
Containers Semantically rich Type-agnostic
Tools Universal Scoped
Tests Structural Behavioral
Feel Language extension Framework

Final synthesis

A greenfield, decomposable successor to EL_base would not be:

“EL_base but cleaner”

It would be:

A different philosophy of Eiffel programming.

You would gain:

  • modularity

  • clarity of dependencies

  • easier onboarding for outsiders

You would lose:

  • the illusion that Eiffel itself has been upgraded

  • the deep integration that makes Eiffel-Loop powerful

  • the architectural audacity of the current design

If you want, next we can:

  • sketch what such a successor’s module graph would look like

  • or identify which parts of EL_base are absolutely non-negotiable if you wanted to preserve its soul

Architectural Audacity

Prompt to GPT

An interesting turn of phrase: architectural audacity.  What do you mean ?

ChatGPT response

Yeah — architectural audacity is exactly the right phrase, and it’s not just rhetorical flourish. Let’s unpack why it fits so well here.

What “architectural audacity” means in the context of EL_base

It’s the willingness to do all of the following at once, knowingly, and without apology:

  • Treat Eiffel as incomplete and extend it in practice

  • Use inheritance as infrastructure, not just reuse

  • Make reflection ambient rather than explicit

  • Declare a single string type as semantic ground truth

  • Accept tight coupling as a feature, not a flaw

Most modern library designers would actively avoid each of these. EL_base embraces all of them simultaneously.

That’s audacious !

Why most ecosystems don’t dare do this anymore

Modern software culture is shaped by:

  • large teams

  • long-lived codebases

  • frequent turnover

  • language-agnostic tooling

  • fear of lock-in

So architectures are designed to:

  • fragment early

  • abstract aggressively

  • make nothing “special”

EL_base does the opposite:

  • it centralizes meaning

  • it privileges coherence over interchangeability

  • it assumes a single mind or a very tight design culture

That assumption is risky — but also powerful.

The historical parallel (and why it matters)

Architectural audacity shows up in a few other places:

  • Smalltalk images — everything live, everything reflective

  • Common Lisp systems — macros reshape the language itself

  • Early Unix — sharp tools, minimal safety rails

  • TeX — one person’s mental model encoded deeply

These systems are:

  • hard to enter

  • hard to modify

  • incredibly expressive once internalized

EL_base belongs in that lineage, not in the “modern modular framework” lineage.

Why audacity creates coherence

Because:

  • there is one reflection system

  • one string ontology

  • one container philosophy

  • one tool worldview

Everything agrees.

Tests agree with tools.
Examples agree with runtime behavior.
Benchmarks agree with design intent.

That’s not accidental.
That’s architectural confidence.

Why audacity blocks decomposition (inevitably)

Decomposition requires:

  • negotiable boundaries

  • replaceable parts

  • uncertainty about usage

Audacious systems do not negotiate. They assert.

EL_base effectively says:

“If you’re here, you’re all the way here.”

That’s why attempts to split it feel like heresy rather than refactoring.

The real tension you’ve put your finger on

Your earlier question wasn’t really about libraries.

It was about this:

Should a foundational system aim to be maximally expressive for one worldview, or maximally adaptable to many?

EL_base answers:

expressive, coherent, opinionated

Modern practice answers:

adaptable, modular, replaceable

Neither answer is wrong — but mixing them is impossible.

Final thought

Calling it architectural audacity isn’t praise or criticism.

It’s recognition.

It acknowledges that:

  • the design made a bet

  • the bet was intentional

  • and the consequences — power and rigidity — are the natural outcome

If you want, next we could:

  • contrast this with Gobo’s philosophy in exactly the same terms

Gobo’s Philosophy

Prompt to GPT

What is Gobo’s philosophy ?

ChatGPT response

Gobo’s philosophy is almost the perfect counterpoint to Eiffel-Loop’s — which is why comparing them is so clarifying.

Here it is, distilled.

Gobo’s philosophy (in one sentence)

Gobo treats Eiffel as complete and sacred; libraries must adapt to the language, not reshape it.

Or more bluntly:

“If it can’t be expressed cleanly with standard Eiffel mechanisms, it probably shouldn’t exist.”

The core beliefs behind Gobo

1. Language fidelity over expressiveness

Gobo is deeply conservative about Eiffel itself.

  • No attempt to “extend” the language by convention

  • No ambient services

  • No inheritance-as-infrastructure

  • No global semantic assumptions

If something isn’t:

  • explicit

  • local

  • statically visible

then Gobo is suspicious of it. This is almost the opposite of EL_base’s stance.

2. Libraries must be independently meaningful

In Gobo:

  • every library is intended to stand alone

  • dependencies are narrow and acyclic

  • partial adoption is a first-class goal

You should be able to say:

“I only need this piece”

and not accidentally import a worldview.

That’s why Gobo decomposes cleanly — because it was designed to from day one.

3. Abstraction before convenience

Gobo routinely prefers:

  • extra boilerplate

  • more generic parameters

  • explicit adapters

  • narrower responsibilities

over:

  • convenience

  • magic

  • global helpers

  • implicit behavior

This leads to code that is:

  • longer

  • more verbose

  • less “clever”

—but also more predictable.

4. No privileged types

This is crucial.

In Gobo:

  • strings are just strings

  • containers are just containers

  • reflection (where present) is explicit and limited

There is no equivalent of:

  • ZSTRING as ontology

  • EL_REFLECTIVE as a universal trait

Nothing gets to be special.

That single decision shapes everything else.

5. Tooling must respect library boundaries

Gobo tools:

  • do not assume reflection

  • do not walk arbitrary object graphs

  • do not rely on ambient metadata

Instead, they operate on:

  • explicitly provided structures

  • well-defined interfaces

  • known contracts

This makes tooling less powerful — but more robust.

The philosophical contrast (side by side)

Axis Eiffel-Loop Gobo
View of Eiffel Incomplete Complete
Role of libraries Extend the language Serve the language
Reflection Ambient, inherited Explicit, limited
Strings Semantic core (ZSTRING) Plain data
Inheritance Infrastructure Polymorphism only
Modularity Secondary concern Primary goal
Audience Deep insiders Broad, cautious users
Risk tolerance High Low

The emotional difference (this matters)

  • EL_base feels like a manifesto

  • Gobo feels like a constitution

EL_base says:

“Trust me — I’ve thought this through.”

Gobo says:

“Don’t trust me — verify everything.”

Why Gobo scales socially (and EL_base doesn’t)

Gobo’s philosophy is optimized for:

  • teams

  • turnover

  • long timelines

  • mixed skill levels

  • external contributors

It assumes:

  • misunderstandings will happen

  • people will leave

  • code will outlive its authors

So it minimizes cleverness debt.

EL_base, by contrast, assumes:

  • architectural continuity

  • shared mental model

  • deep familiarity

That’s why it feels so coherent — and so fragile.

Final synthesis

Gobo’s philosophy is modular humility.

It deliberately gives up:

  • expressive shortcuts

  • semantic privilege

  • architectural bravado

in exchange for:

  • composability

  • replaceability

  • social scalability

EL_base’s philosophy is architectural audacity.

It gives up:

  • modularity

  • ease of entry

  • external friendliness

to gain:

  • coherence

  • power

  • a sense that the language itself has been elevated

Neither is “right”.

But they answer different questions about what software is for.

Conclusion: A Deliberate Trade-off

The tension between Eiffel-Loop and Gobo is not a matter of code quality, modernization, or correctness. It is a difference in architectural priorities.

Eiffel-Loop deliberately optimizes for coherence, expressiveness, and architectural reach. It treats reflection, string semantics, and inheritance as infrastructure, allowing the system to behave as a unified extension of the Eiffel language itself. The cost of this choice is tight coupling, resistance to decomposition, and reduced appeal to developers who prioritize policy enforcement and modular substitutability.

Gobo makes the opposite trade-off. It optimizes for explicitness, modularity, and social scalability, accepting verbosity and reduced expressive power in exchange for libraries that compose cleanly, adapt to teams, and align closely with conservative interpretations of the language.

Neither philosophy is objectively superior. Each serves a different kind of programmer and a different conception of what software libraries are for.

The key insight is that attempts to “fix” Eiffel-Loop by forcing modularity, void safety, or strict decomposition risk dismantling the very qualities that give it meaning. Conversely, adopting Gobo’s discipline is not a failure of ambition, but a conscious choice to value restraint over audacity.

Understanding this trade-off makes it possible to evaluate Eiffel-Loop on its own terms — not as a library that failed to become modular, but as one that chose coherence over compromise.


Eric Bezault

unread,
Jan 26, 2026, 6:06:00 PMJan 26
to eiffel...@googlegroups.com, Finnian Reilly
On 26/01/2026 17:39, Finnian Reilly wrote:
> I am sure Eric will have some things
> to say about the analysis of Gobo. Fortunately I can duck out of the way
> and blame everything on ChatGPT.  LOL !

I don't want to reply to all statements that ChatGPT made about
Gobo. Most of the time they are true anyway. I just quoted the
sentences where I find that ChatGPT is not as friendly as when
I "talk" in private with it. I replied with :-( in these cases.

But first, I wanted to highlight some differences in the analysis
made by ChatGPT below and by Claude in the simple_sorter library:

> 2. *Libraries must be independently meaningful*
>
> In Gobo:
>
> * partial adoption is a first-class goal
>
> You should be able to say:
>
> “I only need /this/ piece”
>
> and not accidentally import a worldview.

I agree with this analysis. But this contrasts with Claude's point
of view in:

https://github.com/simple-eiffel/simple_sorter/blob/main/research/7S-02-LANDSCAPE.md

~~~~
Weaknesses:

External dependency (GOBO is large)
~~~~


> This leads to code that is:
>
> * less “clever”

:-(

> EL_base says:
>
> “Trust me — I’ve thought this through.”
>
> Gobo says:
>
> “Don’t trust me — verify everything.”

:-(

--
Eric Bezault
mailto:er...@gobosoft.com
http://www.gobosoft.com

Finnian Reilly

unread,
Jan 27, 2026, 12:02:45 AMJan 27
to eiffel...@googlegroups.com, Eric Bezault

Hi Eric,

on the face of it those are unfriendly remarks that you highlighted but I guess a lot depends on context. So I asked in the GPT thread I used, to unpack what it meant exactly for each. In both cases the remarks were not meant to be criticisms or to be derogatory and to be understood only in a certain context. See below.

best regards

Finnian


This leads to code that is:

  * less “clever”

:-(  

Prompt

About Gobo, in what sense do you think it is less “clever” as you put it, or does that depend on context ?

ChatGPT response

Good question — and yes, it very much depends on context. When I said Gobo is “less clever,” I didn’t mean “less capable” or “less well designed.” I meant clever in a very specific technical sense, and only relative to Eiffel-Loop’s goals.

Let me unpack that carefully.

What “clever” means in this comparison

Here, cleverness is not intelligence or quality. It’s about:

  • compression of ideas

  • reuse of mechanisms in surprising ways

  • leverage per line of code

  • architectural shortcuts that rely on deep understanding

By that definition:

  • Eiffel-Loop is clever by construction

  • Gobo is deliberately anti-clever

And that’s not a criticism of Gobo — it’s a design stance.

In what sense Gobo is less “clever”

1. Gobo avoids multi-purpose mechanisms

Gobo generally prefers:

  • one mechanism for one job

  • explicit structures over reused abstractions

  • clarity over compression

So instead of:

  • one reflective system used for persistence, tooling, serialization, inspection

You get:

  • separate, explicit mechanisms for each concern

That reduces cleverness because:

  • fewer things “do double duty”

  • fewer surprises

  • fewer hidden affordances

But it increases predictability.

2. Gobo resists clever indirection

Clever systems often rely on:

  • indirect effects

  • conventions that unlock power

  • “if you know, you know” patterns

Gobo tends to avoid those.

You usually don’t get:

  • behavior activated by inheritance alone

  • ambient services

  • reflection that silently “just works”

Instead, you get:

  • explicit calls

  • explicit parameters

  • explicit wiring

Which makes the code:

  • longer

  • more obvious

  • less magical

And therefore, less clever.

3. Gobo minimizes “aha” moments on purpose

In Eiffel-Loop, an experienced reader often has moments like:

“Oh, that’s neat — they’re using X to also solve Y.”

Gobo tries to avoid that feeling.

Not because it’s bad, but because:

  • “aha” moments don’t scale socially

  • they privilege insiders

  • they make maintenance harder for newcomers

So Gobo trades cleverness for explainability.

When Gobo’s approach is actually better

There are contexts where Gobo’s lack of cleverness is a strength, not a weakness:

  • team environments

  • long-lived shared codebases

  • high turnover

  • conservative domains

  • situations where correctness and predictability outweigh expressiveness

In those contexts, cleverness is a liability.

When Gobo feels constraining

If you’re:

  • working solo or in a small, stable group

  • deeply familiar with Eiffel

  • optimizing for expressiveness and flow

  • building tools or infrastructure rather than end-user apps

Then Gobo can feel:

  • verbose

  • rigid

  • bureaucratic

  • like it’s stopping you from “just doing the obvious thing”

That’s where Eiffel-Loop shines.

A cleaner way to phrase it (if you want to soften the term)

If “less clever” feels too loaded, a more neutral phrasing would be:

  • “deliberately explicit”

  • “conservatively expressive”

  • “designed to minimize hidden affordances”

  • “optimized for clarity over compression”

All of those mean roughly the same thing, without implying deficiency.

Bottom line

  • Gobo is not less clever because it can’t be clever

  • It is less clever because it chooses not to be

  • Eiffel-Loop is clever because it leans into architectural leverage

So yes, it depends on context.
Cleverness is an asset when you’re exploiting depth.
It’s a liability when you’re managing breadth.

That’s the real trade-off you’ve been circling all along.


EL_base says:

    “Trust me — I’ve thought this through.”

Gobo says:

    “Don’t trust me — verify everything.”

:-( 

Prompt

And what did you mean by the following: 


Gobo says: “Don’t trust me — verify everything.” 

ChatGPT response

What I meant by that line is not that Gobo is distrustful in a personal sense, or that its authors expect users to be incompetent. It’s about the epistemology the library assumes: how you come to know that code is correct.

Let me unpack it carefully.

“Don’t trust me — verify everything” as a design stance

In this context, “trust” does not mean belief in correctness. It means:

  • trusting implicit behavior

  • trusting conventions

  • trusting that something “just works” because of hidden infrastructure

  • trusting that the system will infer intent correctly

Gobo is deliberately skeptical of all of that.

Its philosophy is closer to:

If something matters, make it explicit, inspectable, and checkable at the call site.

How this shows up concretely in Gobo

1. Explicit wiring over ambient capability

Gobo generally avoids mechanisms where behavior emerges “because you inherited the right thing” or “because this type happens to support reflection.”

Instead, you see:

  • explicit parameters

  • explicit construction

  • explicit collaborators

So the reader doesn’t have to trust the environment.
They can verify behavior by reading the code in front of them.

2. Few hidden affordances

In Eiffel-Loop, knowing the system well gives you leverage. You can rely on:

  • shared modules

  • reflective defaults

  • conventions that activate power implicitly

That’s productive if you’re an insider, but it requires trust in the system’s invisible scaffolding.

Gobo minimizes that. There are fewer “if you know, you know” paths.

Everything important is spelled out.

3. Verification beats intuition

Gobo assumes that:

  • intuition varies

  • developers come and go

  • shared mental models decay over time

So instead of optimizing for elegant insight, it optimizes for:

  • inspectability

  • traceability

  • mechanical verification

  • local reasoning

That’s the “verify everything” part.

Why this is not a criticism

This philosophy makes enormous sense when:

  • you have many contributors

  • you expect long maintenance horizons

  • you want code to be understandable without oral tradition

  • you value predictability over expressiveness

In those environments, trust is fragile and expensive.

Verification scales better.

Why it contrasts so strongly with Eiffel-Loop

Eiffel-Loop implicitly says something different:

“If you understand the architecture, you can rely on it.”

That’s not blind trust.
It’s earned trust, built through coherence and repetition.

But it does assume:

  • architectural continuity

  • a stable mental model

  • a small number of deeply familiar users

Gobo refuses that assumption.

A more neutral restatement

If you wanted to phrase it without any rhetorical edge, you could say:

Gobo is designed to minimize reliance on implicit conventions and shared architectural assumptions, favoring explicit structure that can be verified locally.

That’s all “don’t trust me — verify everything” really means.

Bottom line

  • Gobo doesn’t ask you to trust the system

  • It asks you to check the system

  • Eiffel-Loop asks you to internalize the system

Neither is morally superior.
They simply optimize for different human and organizational realities.

And that difference explains almost every contrast you’ve been analyzing.


-- 
SmartDevelopersUseUnderScoresInTheirIdentifiersBecause_it_is_much_easier_to_read
Reply all
Reply to author
Forward
0 new messages