Live data from Hacker News

Cyclic dependencies are evil (2013)

fsharpforfunandprofit.com

61–70 of 125 posts

Re: Cyclic dependencies are evil (2013)

#61

Earlier quoted context omitted.

If I may, that sounds horrifying. Please, for the sake of my sanity and the IDE, always do things at compile time rather than runtime if you can!

If the code is implementing against interfaces, why would late binding mess up your IDE experience at all?

My heart sinks whenever I need to spend ten minutes trying to work out which of the three different implementors is actually going to be called on a particular code path. For about a week of December, my work was solely spelunking to track down which implementations of an interface in C# were dead code and so on.

Re: Cyclic dependencies are evil (2013)

#62

Earlier quoted context omitted.

I think the OP is overly dogmatic and I agree with you that sometimes you just need circular dependencies That said, I don't see what circular dependencies have to do with reflection, much less a functional style? For a trivial example, Rust lacks reflection but the following (functional-ish) code works just fine: mod ModA { use crate::ModB::B; pub struct A { ref_to_b: Option > } pub fn into_b(a: A) -> Option > { a.r…

Could you give an example of a domain that naturally requires circular dependencies? I have been trying lately to practice seeing outside the functional-programming-tinted lenses, but I need a bit of help to do so :)

I think the GP's example is pretty reasonable. And like I said, I still don't really see what this has to do with FP. Clearly F# has trouble with it, but so does C++

Re: Cyclic dependencies are evil (2013)

#63
post #60
post #3

Language constraints aside, the real world is not something that can be cleanly modeled without the notion of circular dependencies between things. Not very many real, practical activities can be truly isolated from other closely-related activities and wrapped up in some leak-proof contract. Consider briefly the domain model of a bank. Customers rely on Accounts (I.e. have one or many). Accounts rely on Customers (i.…

In the functional paradigm, language constraints aside, to model this "story" would need these: - The definition of Account - The definition of Customer - A ledger consisting of: List of Account, List of Customer, List of Account-Customer relations A clerk works on the records on the ledger with one hand and one pen, a metaphor for the service process working on the data in the database. An act, such as money transfe…

> `customer.accountService.createAccount(newAccountData)`

I believe that most OO implementations would read

    accountService.createAccount(customer, newAccountData)
Care to elaborate if that was the main point of the clerk's schizophrenia criticism? Or if I'm misinterpreting just call me dumb, haha.

Re: Cyclic dependencies are evil (2013)

#64
post #42

Earlier quoted context omitted.

Reflection allows you to put the interfaces to Account and Customer into a shared module and the business logic implementations into their own mutually independent modules, thus removing the cyclic compile time dependency. You "wire up" the implementations at runtime, using reflection.

If I may, that sounds horrifying. Please, for the sake of my sanity and the IDE, always do things at compile time rather than runtime if you can!

It's called the "dependency inversion principle". People don't like to call it "reflection", and heap various layers like XML or dependency injection annotions on it, but technically, it comes down to reflection at runtime, as far as I've seen.

It certainly has its cost in additional complexity through indirection, but it's better than creating cyclic dependencies or giant balls of mud.

https://en.m.wikipedia.org/wiki/Dependency_inversion_princip...

Re: Cyclic dependencies are evil (2013)

#65
post #64

Earlier quoted context omitted.

If I may, that sounds horrifying. Please, for the sake of my sanity and the IDE, always do things at compile time rather than runtime if you can!

It's called the "dependency inversion principle". People don't like to call it "reflection", and heap various layers like XML or dependency injection annotions on it, but technically, it comes down to reflection at runtime, as far as I've seen. It certainly has its cost in additional complexity through indirection, but it's better than creating cyclic dependencies or giant balls of mud. https://en.m.wikipedia.org/wik…

No, you don’t need reflection or annotations to use dependency inversion. Why do you think so?

Re: Cyclic dependencies are evil (2013)

#66

Earlier quoted context omitted.

If I may, that sounds horrifying. Please, for the sake of my sanity and the IDE, always do things at compile time rather than runtime if you can!

If the code is implementing against interfaces, why would late binding mess up your IDE experience at all?

I've seen people learning about dependency inversion from a book called "Clean Architecture", then proceeding to apply it to every bit of code they write, to make it "clean". It makes code difficult to trace by reading alone. Indirection may be cheap, but it adds up.

Re: Cyclic dependencies are evil (2013)

#67
post #54
post #7

Earlier quoted context omitted.

In F#, you would naturally approach this by defining a Customer independent of the Account (e.g. just containing a name and address), and an Account independent of the Customer (e.g. just containing an ID), and then a Bank which is a mapping of Account to Set . What you see as a cyclic dependency, I see as a data type that you haven't reified.

> and then a Bank which is a mapping of Account to Set The problem is that this only lets you get customers from accounts, and not vice-versa. And if you add a Map > to the Bank, you now have to ensure the mappings are synchronized at all times. Which, to be fair, is very straightforward as long as Bank is immutable, but still kind of annoying. But considering how incredibly common many-to-many relationships are in b…

In the in-storage form (database), the mappings is synchronized at all times.

Many-to-many relationships in the purest form is described as records of ItemAId/ItemBId pairs. `List`. There isn't any cyclical relationship in this form.

From `List` one can derive `Map>` and `Map>`. Bank can have copy of both mappings and use them as double index, synchronizing both mappings as operations goes by, while at the same synchronizing both mappings to the in-storage form. Or not!

We're talking mostly about data-modelling in a programming language, which applies to the in-memory form. `Customer { accounts: Set }` and A `Account { customers: Set }` is its in-memory form, a layer of indirection from its actual form, the in-storage `List`.

If informations of Accounts, Customers, and the many-to-many relationship of both are laid flat in its purest, source-of-truth form, the in-storage database entries, why are people suggesting that there is/should be a cyclical relationship in its representative form, the in-memory objects?

Re: Cyclic dependencies are evil (2013)

#68

Earlier quoted context omitted.

Could you give an example of a domain that naturally requires circular dependencies? I have been trying lately to practice seeing outside the functional-programming-tinted lenses, but I need a bit of help to do so :)

I think the GP's example is pretty reasonable. And like I said, I still don't really see what this has to do with FP. Clearly F# has trouble with it, but so does C++

I don't think the GP's example is reasonable, and nor would an SQL-writer. Could you give something I will find it harder to wriggle out of?

Re: Cyclic dependencies are evil (2013)

#69
post #11
post #3

Language constraints aside, the real world is not something that can be cleanly modeled without the notion of circular dependencies between things. Not very many real, practical activities can be truly isolated from other closely-related activities and wrapped up in some leak-proof contract. Consider briefly the domain model of a bank. Customers rely on Accounts (I.e. have one or many). Accounts rely on Customers (i.…

Sometimes I read conversations about software engineering concepts by career developers and I get this sense that there is this entire hidden world of other engineers that I have somehow managed never to encounter. Every engineer I've ever met who has been doing it for more than a couple years universally decries circular dependencies. Every one of them has come to that opinion via hard won experience dealing with re…

To me, the parent is describing a functional circular dependency that we all have to live with, but when we’ll design the system it will be masqueraded in a many to many association in a third object/table and we’ll proudly say “we have no circular dependencies”.

To me both are technically true, reality is messy, and we hide the mess under imaginary constructs.

Post reply on HN