DCI (or close to) in pure Java 8+ ?

91 views
Skip to first unread message

Alexandru Balmus

unread,
Sep 20, 2023, 4:32:36 AM9/20/23
to object-composition
Hi everyone! 

I've been exploring ways to do DCI in Java without the use of reflection (which is usually discouraged and it's not that fun to use anyway) or third party libraries (because some may require special approval to be included in real projects, which may not always be granted). 
On the Wikipedia page I've seen the suggestion to use Java 8+ interfaces with default methods to implement roles. I've been thinking about how that would work out and in the end I've settled for a combination of generics, interfaces with default methods and lambda expressions as syntactic sugar for anonymous inner classes that would implement the roles interfaces.
 
The result? 
While true DCI is currently impossible (?) to achieve in pure Java, to me it seems the approach I've taken is reasonably close to the goals of DCI if you want to stick to this language. 

Of course, I'm still new to DCI so it's possible I may be wrong about that conclusion, and that's why some feedback would be greatly appreciated. Here is a link to a GitHub repo where I've attempted to recreate the famous bank accounts example: https://github.com/alexbalmus/dci_java_playground 

Please let me know your thoughts. Thank you!

Alexandru Balmus

unread,
Oct 30, 2023, 5:13:38 AM10/30/23
to object-composition
Hello again!

It could be that everyone is galactically busy - that's understandable. Still, it would also be galactically awesome if someone could squeeze a little bit of time for some feedback on this. :) 

Thank you!

Alex Balmuș

Matthew Browne

unread,
Oct 30, 2023, 9:01:40 AM10/30/23
to object-co...@googlegroups.com, Alexandru Balmus

Hi Alex,
I have very little experience programming in Java (from a long time ago), but it looks like the Java 8 features you're using have made for nicer syntax.

It sounds like you've already been reading up on DCI and the pitfalls of wrapper implementations, but just to be clear, it's not actually DCI if object identity isn't preserved. A wrapper implementation can still be useful if it's the only option though, which I always thought was the case for Java...but now that I looked up Java interfaces with default methods I'm not so sure.

It looks like Java interfaces with default method work similarly to traits (e.g. Scala traits). There's an old thread about them here in this group:

https://groups.google.com/g/object-composition/c/gPXGKOtgMgU/m/lKZi6lTIwmYJ

As you can see from that thread, there are challenges with making them work well for DCI.

I wonder if a "reverse wrapper" technique would be possible in Java 8 (which does preserve object identity). This is where the data object wraps the role instead of the other way around. But that's only helpful if you have a way of intercepting method calls, as I did in my PHP implementation where I used PHP's "magic method" __call() in this part of my implementation. As I said I don't really know Java, but maybe aspect-oriented programming using a tool like AspectJ would be worth looking into in case that's possible?

In general, there are two approaches to making traits or abstract base classes work for "true" DCI (without macros or source code transformation):

1. The reverse wrapper technique mentioned above (uncommon; the only DCI implementations I know are using this are in PHP)

2. Somehow using the language's type system to ensure that only the appropriate roles can be called within a Context

In both cases, the traits have to be added statically somewhere, you're just doing some trickery to ensure they're only available where they should be. And you either have to accept the possibility of name conflicts of methods from different roles that could potentially be added to the same object (forcing you to rename one of them), or using a naming convention that includes the role name, e.g. `source.source_transfer()`, which is a bit verbose and annoying.

I'm not sure if any of this will help improve your Java implementation given the constraints of the language, but those are some things to think about.

--
You received this message because you are subscribed to the Google Groups "object-composition" group.
To unsubscribe from this group and stop receiving emails from it, send an email to object-composit...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/object-composition/a3138fa4-d2cc-4a40-a31f-f07b9d27a330n%40googlegroups.com.

Lund Soltoft

unread,
Oct 30, 2023, 10:28:01 AM10/30/23
to object-co...@googlegroups.com
I’m not a wiz Java  semantics. What would happen if an object plays role_an and role_b and you do a reference comparison between role_an and role_b? Would that yield true or false?

Mvh
Rune

Den 30. okt. 2023 kl. 14.01 skrev Matthew Browne <mbro...@gmail.com>:



Alexandru Balmus

unread,
Oct 30, 2023, 12:42:29 PM10/30/23
to object-composition
Thank you so much for your replies!

A few thoughts:

For Matthew:

- Thanks for sharing that link to the older post related to this subject; oddly enough, a search for "dci java" or "java dci" did not reveal it to me when I first searched this group; the concerns raised there are indeed valid if one would attempt true DCI, therefore if "any data object that potentially plays multiple roles in multiple contexts would need to statically declare to implement all those role interfaces", then indeed conflicts could occur; however in my wrapper approach (while having drawbacks) I don't go down this path;

- The "reverse wrapper" idea is very interesting, I'll try to think about if/how it could be implemented; one concern I have off the top of my head would be the fact that objects should have some role wrapping mechanism build into them and this might not be feasible in projects that have a certain maturity but did not start out with DCI in mind; while striving for a true DCI implementation is a noble goal, I guess I'm more interested in trying to bring as many of DCI's cool features (Contexts that clearly reflect use cases, thinking in terms of roles...) to any Java project, regardless if it's one starting from scratch or a mature one that is less flexible to change, so I'm really open to making reasonable compromises;

- Preserving object identity, in the sense of being able to compare object references is indeed challenging when trying to do DCI in Java, however I'm wondering just how important this really is given:

a) regarding DCI, while I'm still new to it and perhaps I'm not getting certain things, reading the paper https://fulloo.info/Documents/ArtimaDCI.html it seems to me that Roles also act as identifiers for objects in a given Context, so I'm not sure what identity related problems could occur inside a Context; also, I wouldn't worry about method naming conflicts at Context level because Roles are/should be confined to a given Context and therefore should be crafted as such as to not introduce conflicts (unit tests could help enforce this), so if Roles are only temporarily assigned to objects in a particular Context, I would imagine we should be fine;

b) since I'm dealing with Java and nowadays 99.9% of Java projects are web apps that persist entities (the Data objects) usually in a relational DB and use an ORM for that, in this case comparing object references is not something that's considered anyway because what might look like a reference to some object might actually be a reference to some lazy-loading proxy dynamically generated by the ORM, which would trigger a database fetch on first access; so when dealing with ORM managed entities, identity would be checked against a certain persistent property of that entity, which in my wrapper implementation would be accessed using the self() method;

Thanks again for your thoughts and suggestions!

For Rune:

As per your question "What would happen if an object plays role_an and role_b and you do a reference comparison between role_an and role_b? Would that yield true or false?", the answer would be false, but:

a) how I approach the idea of multiple roles in my implementation is by defining a new Role interface that inherits from multiple other Role interfaces and in the end there would be a single object (implementing that interface) that would wrap the Data object; I know inheritance is discouraged in DCI, but I'm only aiming for minimal usage of inheritance just for combining multiple roles and avoiding the situation you've described.

b) as I've answered above to Matthew, in Java when dealing with ORM managed entities (the Data objects), you wouldn't rely on comparing object references anyway.

Thank you for raising this concern!

Alexandru Balmus

unread,
Oct 30, 2023, 12:53:31 PM10/30/23
to object-composition
My apologies Lund Soltoft, it seems I've misinterpreted your name when I replied earlier (thought it was "Rune"). For some reason the Google Groups UI is not showing me the names upfront and it's only when I looked in the email notification I would see it.

Matthew Browne

unread,
Oct 30, 2023, 10:01:09 PM10/30/23
to object-co...@googlegroups.com, Alexandru Balmus

Hi Alex,

I'll try to think about if/how it could be implemented; one concern I have off the top of my head would be the fact that objects should have some role wrapping mechanism build into them and this might not be feasible in projects that have a certain maturity but did not start out with DCI in mind

Yes, that is one disadvantage of the approach...the other example would be classes from third-party libraries that you would have to subclass first if you wanted to be able to use their objects as role players. I didn't find it to be an issue in practice but your mileage may vary.

Preserving object identity, in the sense of being able to compare object references is indeed challenging when trying to do DCI in Java, however I'm wondering just how important this really is

I imagine you're aware that there are a number of operations involving lists, hash maps, etc, that depend on consistent object identity to work correctly (in OO systems in general). The canonical DCI example that showcases the need to maintain object identity is an implementation of Dijkstra algorithm (

Having said that, DCI is really more about how you think about the system than it is about the implementation details. Even with a very imperfect implementation, I think you can still get a lot out of thinking in terms of DCI and approaching your code from that perspective. So from a practical standpoint and the limitations of the language, I think what you said makes sense and I would probably think similarly. I would still definitely explore all your options for solving the identity problem, and even if you decide to stick with your original solution, you'll learn more about DCI and its implementation patterns along the way.

Cheers,
Matt

Lund Soltoft

unread,
Oct 31, 2023, 1:37:21 AM10/31/23
to object-co...@googlegroups.com


> Den 30. okt. 2023 kl. 17.42 skrev Alexandru Balmus <alexb...@gmail.com>:
>
> a) how I approach the idea of multiple roles in my implementation is by defining a new Role interface that inherits from multiple other Role interfaces and in the end there would be a single object (implementing that interface) that would wrap the Data object; I know inheritance is discouraged in DCI, but I'm only aiming for minimal usage of inheritance just for combining multiple roles and avoiding the situation you've described.

It is more than just a technicality. Object identity is important and some rather surprising bugs might arise if not preserved. A lot of libraries depend on it, so you can’t mitigate the issues by how you code, nor can you even in you own code sufficiently guard against the situation I described if a) the code is complex and/or of sufficient volume b) a set of objects can play any of a number of roles that interact.

Mvh
Rune
(Which is indeed my name)

Alexandru Balmus

unread,
Oct 31, 2023, 3:05:16 AM10/31/23
to object-composition
Matt and Rune,

Thank you both for the advices and issues raised, which I will think about some more in order try to further improve the solution.
I realize I was ambiguous when talking about comparing object references: indeed object identity is very important, and in Java we need to take care of properly implementing the equals() and hashcode() methods. So in the case of my implementation, the easiest(not necessarily the best) approach would be to reach out to the equals() method of the wrapped object. And if dealing with lists/hashmaps I would try to just use the Data objects and then assign roles as needed to individually extracted objects (after ensuring identity). Not pretty, I agree, so I'll think about further improvements.

Cheers!

Alex Balmuș 

Egon Elbre

unread,
Nov 11, 2023, 2:46:20 PM11/11/23
to object-composition
It looks like many of these emails had landed to spam for me, for some reason. Anyways, I had some torture tests that tired to cover the some issues with implementing DCI in https://groups.google.com/g/object-composition/c/MniT_0RRPic/m/48oJ59zgCgAJ.

+ Egon

Reply all
Reply to author
Forward
0 new messages