• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Joseph.N

Confusion about Law of Demeter

27 posts in this topic

Does this code violates the Law of Demeter?

[code]

void object::foo()
{
//...

std::string s1 = "Hello World!";

string s2 = s1.substr(0, 5);

// process string s2...
//.....
}
[/code]

The function foo() calls a function on object string s1, which returns s2 to be further processed in this function...This looks like violating the Demeter law since it calls functions on an object
returned by another function. If so then what should be the alternative?

Thanks.
0

Share this post


Link to post
Share on other sites
s1 is stored locally within foo(), so anything that accesses s1's member functions is legit within foo().

A violation would be if you had something like:

[code]struct bletch
{
bletch(const std::string& contents)
: Something(contents)
{ }

std::string Something;
};

void foo()
{
bletch b;
std::cout << b.Something.substr(0, 5); // Directly accessing a method of bletch's members is forbidden
}[/code]

However, the practical applications of the Law of Demeter are often limited. It is much more useful to work in terms of [i]layered abstractions[/i] than strict adherence to LoD style. Rather than demanding that you never access nested members, for instance (which can become really impractical in real code), you build everything like layers of lasagna. One layer may access the layer below it, but no layer may access the layer above it. Reaching more than one layer down is permissible but should be minimized when it makes sense.
1

Share this post


Link to post
Share on other sites
Short version, don't do this:

[code]foo->bar->baz->sayHello();

foo().getBar().getBaz().sayHello()[/code]

Stick to single level of indirection (aka one dot or one arrow).
0

Share this post


Link to post
Share on other sites
Now this triggered another question. If the data member Something is returned by getters as a reference which is the case of managed languages like C# or JAVA, then it's a violation of the Demeter law. However, in case of C++ where we can get a copy of the object it's not. So although both languages used getters, it's the language semantics that determines this kind of violation. Correct?
0

Share this post


Link to post
Share on other sites
Not quite.

[code]foo.GetSomething().bar(); // violation
foo.DoBarOnSomething(); // ok[/code]

This holds regardless of language semantics. It doesn't matter what GetSomething() returns (a value, a reference, a const reference) because the very existence of GetSomething() means you're violating the one-degree-of-separation clause of the Law of Demeter.

Remember, it is better to tell an object to do something to itself than to ask it for information so you can do the same operation externally.
0

Share this post


Link to post
Share on other sites
Incorrect. The Law of Demeter isn't about whether the data you're accessing is a copy or a reference, it's about maintaining a coherent abstraction and limiting the impact of change.
0

Share this post


Link to post
Share on other sites
I'm now more confused. In one of the text books, it says that calling a method on an object not created by the function itself violates the law.

In this case

Something s = obj.GetSomething();

s.DoSomething();

Now if "s" was a copy rather than a reference it would be an object created inside the caller method and hence does not violate the Demeter. Otherwise, it's manipulating "obj's" data member directly.
0

Share this post


Link to post
Share on other sites
[quote name='RecycledBytes' timestamp='1314421821' post='4854324']
I'm now more confused. In one of the text books, it says that calling a method on an object not created by the function itself violates the law.[/quote]Clearly that definition is not right as it would mean calling anything on a global variable would be a violation.

It's really all about how many dots or arrows you have following from an object or pointer, in an expression. > 1 = bad.
1

Share this post


Link to post
Share on other sites
Specifically from the "Clean Code," by Robert C. Martin, page 98, where it explains that it's not only about dots...

Something fishy about the law of Demeter???

Any good reference?
0

Share this post


Link to post
Share on other sites
[quote name='RecycledBytes' timestamp='1314465644' post='4854488']
Something fishy about the law of Demeter???
[/quote]
Just that the "Rule of Thumb of Demeter" doesn't sound as cool?
1

Share this post


Link to post
Share on other sites
[quote name='RecycledBytes' timestamp='1314465644' post='4854488']
Specifically from the "Clean Code," by Robert C. Martin, page 98, where it explains that it's not only about dots...

Something fishy about the law of Demeter???[/quote]
Nope. As referenced, consultants need to justify their existence by talking endlessly over pointless metrics.

What else are they supposed to do? Actual work? Stuff that matters?

Java people also like to obsess over stuff like that. If they instead tried solving actual problems, 95% of them would be out of work since their codebases would go from 10 million lines to code to 1000.

Then there's academia, stuck firmly inside their ivory tower floating in an UFO on some faraway planet.
0

Share this post


Link to post
Share on other sites
Interesting!

So there's no solid well-established definition or specification of the Law of Demeter.

Some decent texts about OO designs don't even mention it. I only encountered this term in "how to code nicely" texts ;) so this could be a cosmetic vague principle that serves its purpose only in code-readability realm.
0

Share this post


Link to post
Share on other sites
[quote name='RecycledBytes' timestamp='1314421821' post='4854324']
Now if "s" was a copy rather than a reference it would be an object created inside the caller method and hence does not violate the Demeter. Otherwise, it's manipulating "obj's" data member directly.
[/quote]

I think it's exactly this. if the Something belongs to obj, then tell obj to do whatever needs to be done with it, so that you don't have to care what the Something is. (as ApochPiq said).
Of course it supposes that you can refactor everything. If you don't have control over obj, you can't do much.

It's about a bit more than just readability. And even then, I wouldn't say "only readability", as it's so important !
0

Share this post


Link to post
Share on other sites
[quote name='RecycledBytes' timestamp='1314475279' post='4854534']

So there's no solid well-established definition or specification of the Law of Demeter. [/quote]

It's well-established by academia in many publications.

In practice, the above isn't relevant.

What is relevant is that developers who not only gained design experience but are also able to apply it (aren't constrained by arbitrary management enforced "Best Practices") will write code that builds and runs fast, is understandable and moves project along fast. These are the developers who, among many other factors, might be obeying the law, if it helps them.

[quote]Some decent texts about OO designs don't even mention it.[/quote]

OO is one of most degenerated terms. If it's about any real language, such as .net, Java, PHP or similar, it's not OO. OO is actually well-designed methodology, but sadly no language used today follows it or makes it possible to implement it.


Or put differently. We can discuss details of theoretical OO definition into oblivion. But then:
- language makes it impossible to implement them
- the standard library or other required libraries do not obey them
- platform APIs aren't OO nor can they be mapped to pure OO
- best practices prevents adoption
- it directly violates various code conventions

Nice in theory, but cannot be implement on any real world project.

So over time you take what you can and settle that quality of project is inversely proportional to number of sequential dots. Not ideal, but good enough.

And if this is for some exam, then you will need to regurgitate whatever the lecturer wants to hear, since academia hasn't reached consensus (again, in practice) on what it actually means.

---
Why yes, my Cheerios did taste like piss, why do you ask?
0

Share this post


Link to post
Share on other sites
[quote][color=#1C2837][size=2]I think it's exactly this. if the Something belongs to obj, then tell obj to do whatever needs to be done with it, so that you don't have to care what the Something is.[/size][/color][/quote]


Then it's language-semantics dependent. When I get a copy of Something rather than the actual member, then manipulating does not affect the actual object. However if it's a reference, like in C# or Java, then it's definitely accessing internals of the object.


Consider this scenario:


[code]


void PhysicsEngine::CollideWithWorld(const GameCharacter& gameChar)
{
//....

BoundingBox bBox = gameChar.GetMeshBoundingBox();

bool result = Collide(bBox);

//.....
}


[/code]


Here the game characters have to be decoupled from the physics. The first call: GetMeshBoundingBox does not violate the Demeter Law since I'm passing gameChar to the function.

Now obtaining a copy of the bounding box and passing it to the physics engine functions for further processing which could result in a modification in the bounding box itself for collision resposnse wheich I then pass back to the game character to alter its' own mesh...BUT this could be a bigggggg problem if the BoundingBox returned was a reference, where accessing and manipulating it would result in directly manipulating the gameChar internal objects. So yeah language does make a difference.

0

Share this post


Link to post
Share on other sites
[quote name='RecycledBytes' timestamp='1314421821' post='4854324']
Something s = obj.GetSomething();

s.DoSomething();

Now if "s" was a copy rather than a reference it would be an object created inside the caller method and hence does not violate the Demeter. Otherwise, it's manipulating "obj's" data member directly.
[/quote]I don't think it matters whether it's a copy or a reference. The difference between the above and:
obj.GetSomething().DoSomething();
is that the former is like Alice saying to Bob, "Can you deliver this package to Charlie please?" and then saying to Charlie, "Can you open the package, take out the device, and plug it into your computer please?"
Whereas the later is like saying "Bob, can you please deliver this package to Charlie and tell Charlie to open the package, take out the device, and plug it into his computer?".
The main difference being that in the first case the second instruction is given directly to Charlie, not relayed via Bob, or in the case of the code, the method is called directly on s by the function, and whether s is a copy or a reference makes no difference.
[i]Sorry this is a very weak metaphor.[/i]
0

Share this post


Link to post
Share on other sites
[quote name='RecycledBytes' timestamp='1314421821' post='4854324']
I'm now more confused. In one of the text books, it says that calling a method on an object not created by the function itself violates the law.

In this case

Something s = obj.GetSomething();

s.DoSomething();

Now if "s" was a copy rather than a reference it would be an object created inside the caller method and hence does not violate the Demeter. Otherwise, it's manipulating "obj's" data member directly.[/quote]
Nope. The point here is that 's' is not created by this function, it is created by 'obj' (via the 'GetSomething' method).

In other words, the above code is semantically no different than 'obj.GetSomething().DoSomething()', which violates the double-dot rule.
0

Share this post


Link to post
Share on other sites
[quote name='swiftcoder' timestamp='1314478891' post='4854551']
In other words, the above code is semantically no different than 'obj.GetSomething().DoSomething()', which violates the double-dot rule.
[/quote]

As said, languages used in practice do not make it viable to follow such strict principles. Here is a well-designed example:[code]

SqlQuery q = SqlQuery.select("*").from("people").where("id == 100");[/code]Plenty of dots, but no problem.

Violation of law comes from making assumptions about structure of called objects. Here we always call on same *interface*, so the depth remains one.

When doing somehting like:[code]car.getEngine().getTorque()[/code]we make assumptions about engine having torque. This point is blurred due to static typing in most languages. Since we can do compile-time check we know that engine has torque, so everything is seemingly fine. IDEs make a mockery of this even further.

But let's consider a dynamic language or even SmallTalk. getEngine() may return something with torque, something without torque or a cheeseburger. OO does not require strict or static or any kind of typing.

Consider:[code]eval("foo.php/py/lisp").getTorque()[/code]This statement is fine - eval makes something, then takes torque. But counter example would be:[code]eval("foo.php/py/lisp").getEngine().getTorque()[/code]Suddenly we simply guess that an engine has torque, which breaks encapsulation. If we were to make such as assumption, then it would need to be getEngineTorque().

In pure OO, everything is object, so eval could return "1", "func()", instance of Engine, instance of RevvedEngine, torque or text. No assumption of anything can be made, unlike common languages today where return would be typed as IEngine, which obviously has getTorque() engine.

Code completion is partly to blame for this since it encourages deep calls resolved during some compile-time declaration. Dynamic languages are, ironically, better at OO than those commonly touted as OO due to lack of such tooling which doesn't lead to degenerate design.


In same vein, casting exhibits same flaws. One should never cast to gain access or use instanceof/typeof/etc... to try to force or guess existence of some trait. If Engine doesn't have getTorque(), but RacingEngine does, casting should be avoided (unless if required to work around language limitations, which is the norm in Java and most everywhere else). But design or implementation that requires such behavior is poorly designed.
0

Share this post


Link to post
Share on other sites
Alrite. So does this code break the law? :)

[color=#1C2837][size=2][color=#000088]void[/color][color=#000000] [/color][color=#660066]PhysicsEngine[/color][color=#666600]::[/color][color=#660066]CollideWithWorld[/color][color=#666600]([/color][color=#000088]const[/color][color=#000000] [/color][color=#660066]GameCharacter[/color][color=#666600]&[/color][color=#000000] gameChar[/color][color=#666600])[/color][color=#000000]
[/color][color=#666600]{[/color][color=#000000]
[/color][color=#880000]//....[/color][color=#000000]

[/color][color=#660066]BoundingBox[/color][color=#000000] bBox [/color][color=#666600]=[/color][color=#000000] gameChar[/color][color=#666600].[/color][color=#660066]GetMeshBoundingBox[/color][color=#666600]();[/color][color=#000000]

[/color][color=#000088]bool[/color][color=#000000] result [/color][color=#666600]=[/color][color=#000000] [/color][color=#660066]Collide[/color][color=#666600]([/color][color=#000000]bBox[/color][color=#666600]);[/color][color=#000000]

[/color][color=#880000]//.....[/color][color=#000000]
[/color][color=#666600]}[/color][color=#000000]
[/color][/size][/color]
0

Share this post


Link to post
Share on other sites
[quote name='RecycledBytes' timestamp='1314482348' post='4854564']
Alrite. So does this code break the law? :)

[color="#1C2837"][size="2"][color="#000088"]void[/color] [color="#660066"]PhysicsEngine[/color][color="#666600"]::[/color][color="#660066"]CollideWithWorld[/color][color="#666600"]([/color][color="#000088"]const[/color] [color="#660066"]GameCharacter[/color][color="#666600"]&[/color][color="#000000"] gameChar[/color][color="#666600"])[/color] [color="#666600"]{[/color] [color="#880000"]//....[/color] [color="#660066"]BoundingBox[/color][color="#000000"] bBox [/color][color="#666600"]=[/color][color="#000000"] gameChar[/color][color="#666600"].[/color][color="#660066"]GetMeshBoundingBox[/color][color="#666600"]();[/color] [color="#000088"]bool[/color][color="#000000"] result [/color][color="#666600"]=[/color] [color="#660066"]Collide[/color][color="#666600"]([/color][color="#000000"]bBox[/color][color="#666600"]);[/color] [color="#880000"]//.....[/color] [color="#666600"]}[/color] [/size][/color]
[/quote]

Yes.

Instead, the classes should be structured like this:[code]class GameCharacter {
void CollideWithWorld() {
bool result = world->Collide(bBox); // or bBox.Collide(world);
}
private:
BoundingBox bbox;
World * world;
};[/code]
The original code is too small to make any meaningful distinction though, so the above may not seem like a relevant change and World is not defined, so it might be unsuitable abstraction as well.

In practice, very few libraries use such design, especially those concerned with physics, since it represents worst possible design with regard to hardware architecture (aka, slowest possible).
0

Share this post


Link to post
Share on other sites
Ok. Makes sense. But then:

void myClass::foo()
{
....

std::string s2 = s1.substr(1, 3);

char *c = s2.c_str();

char *c2 = global_format(c);

}

Breaks it since the STL could have implemented a function called global_format(const char *) ?
0

Share this post


Link to post
Share on other sites
[quote name='RecycledBytes' timestamp='1314505781' post='4854635']
Ok. Makes sense. But then:

void myClass::foo()
{
....

std::string s2 = s1.substr(1, 3);

char *c = s2.c_str();

char *c2 = global_format©;

}

Breaks it since the STL could have implemented a function called global_format(const char *) ?
[/quote]

C and C++ are not OO languages, so such rules cannot apply. It's impossible to discuss such rules in these languages.

STL is not designed to be OO, even though it respects all the useful properties of SOLID principle. Instead of worrying over pointless laws, look at how and why STL is designed the way it is. It's actually one of best applications of OO concepts today.


Also, these are design guidelines, so discussing them in scope of one function is as useful as discussing structural integrity of a building by looking at a pebble in a brick. Design principles apply to interaction between systems. Design patterns resulted in same disaster. Instead of applying them to design concerns, people spent months refactoring single methods just to meet some unapplicable rules.
0

Share this post


Link to post
Share on other sites
[quote]
Instead of applying them to design concerns, people spent months refactoring single methods just to meet some unapplicable rules.
[/quote]

Exactly. Inapplicable rules. And the reason is that such rules are too general and have fragile inconsistent definitions for the sake of confusion, academia kind of work ;)

It could be more practical for languages like Java, JavaScript and C#, where an object is returned by reference, making the internal data of a class accessible even using getters.

As you mention, C and C++ are not OO in a sense they support a broader range of paradigms.

Thanks for all helping me sorting out the confusion, now it's very clear to me :)
0

Share this post


Link to post
Share on other sites
[quote name='RecycledBytes' timestamp='1314551944' post='4854764']


It could be more practical for languages like Java, JavaScript and C#, where an object is returned by reference, making the internal data of a class accessible even using getters.[/quote]

Getters, by very definition, violate the law as well as its spirit. They are the worst abomination that happened to programming after singletons. "Tell, don't ask".

Look at collision example above, no getters.


References and similar details do not apply, they are implementation details which do not affect the OO principles.
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0