E11054: method chain traverses too many types - extract a function or use a pipeline
What went wrong
This method chain crosses more than 3 type boundaries. Each dot that returns a different type from its receiver creates a structural dependency on an intermediate type. Chains like 'order.getCustomer().getAddress().getCity()' couple this code to Order, Customer, Address, and String simultaneously.
Worked examples
Compilable examples demonstrating this error and the correct fix:
- ek9 -q 731 (What is the type traversal limit and why does EK9 enforce...)
Rationale
- Law of Demeter (Lieberherr 1987): "Only talk to your immediate friends"
- Guo et al. (University of Zurich, WCRE 2011): across five Eclipse sub-projects, Law of Demeter violations correlated with bug-proneness
- Each type transition adds a structural dependency that must be maintained when any intermediate type changes
- Limit: 3 type transitions (same-type chains like String.trim().upperCase() do not count as transitions)
Detection details
- Counts type transitions, not raw dots in the chain
- Same-type chains (String.trim().upperCase()) count as 0 transitions
- Constrained types and their base types are treated as the same type (e.g., EmailAddress constrained from String calling trim() is not a transition)
- The start type is the receiver; each subsequent call that returns a different type increments the counter
- Threshold: more than 3 type transitions triggers the error
How to fix it
- Identify which intermediate types the chain traverses
- Extract a function that encapsulates the multi-step traversal
- Or add a direct accessor to the immediate type that hides the depth
- Consider using stream pipelines where each stage handles one type
Common causes
- Deep object graph traversal (order -> customer -> address -> city)
- Accessing nested configuration (config.getDatabase().getPool().getMaxSize())
- Navigating tree structures through multiple node types
- Reporting code that pulls data from disparate domain objects
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E11054: method chain traverses too many types - extract a function or use a pipeline
#!ek9 defines module error.e11054.bad defines class Location name as String: "Leeds" getName() <- rtn as String: name default operator ? Address location as Location: Location() getLocation() <- rtn as Location: location default operator ? Customer address as Address: Address() getAddress() <- rtn as Address: address default operator ? Order customer as Customer: Customer() getCustomer() <- rtn as Customer: customer default operator ? defines function getDeepValue() -> order as Order <- city as String: String() city: order.getCustomer().getAddress().getLocation().getName()
Fixed: Ask each type for what it knows - give Customer a method for the city
#!ek9 defines module error.e11054.good defines class Location name as String: "Leeds" getName() <- rtn as String: name default operator ? Address location as Location: Location() city() <- rtn as String: location.getName() default operator ? Customer address as Address: Address() city() <- rtn as String: address.city() default operator ? Order customer as Customer: Customer() getCustomer() <- rtn as Customer: customer default operator ? defines function getCustomerCity() -> order as Order <- city as String: order.getCustomer().city()
Questions and answers
These Q&A entries show E11054 and its fix: