The following is an interview question. I came up with a solution, but I'm not sure why it works.
Question:
Without modifying the Sparta class, write some code that makes MakeItReturnFalse return false.
public class Sparta : Place
{
public bool MakeItReturnFalse()
{
return this is Sparta;
}
}
My solution: (SPOILER)
public class Place{public interface Sparta { }}
But why does Sparta in MakeItReturnFalse() refer to {namespace}.Place.Sparta instead of {namespace}.Sparta?
300 (1/5) Best Movie Quote - This is Sparta!
This is SPARTA! is a 2007 meme that originated from a scene from the movie "300" in which Leonidas, the leader of the Spartans, kicks a persian messenger into a hole.
Gerard Butler Says Unexpected Delivery of Iconic '300' Line Made Cast Laugh. In a GQ video posted Monday, actor Gerard Butler explains when he screamed the iconic '300' line "This is Sparta!" that his army almost broke character laughing.
Gerard Butler's tense standoff with a messenger is one of the most memorable moments in 300. In the scene, his character, King Leonidas, shouts “This is Sparta!” before kicking him into a pit of darkness.
But why does
SpartainMakeItReturnFalse()refer to{namespace}.Place.Spartainstead of{namespace}.Sparta?
Basically, because that's what the name lookup rules say. In the C# 5 specification, the relevant naming rules are in section 3.8 ("Namespace and type names").
The first couple of bullets - truncated and annotated - read:
- If the namespace-or-type-name is of the form
Ior of the formI<A1, ..., AK>[so K = 0 in our case]:
- If K is zero and the namespace-or-type-name appears within a generic method declaration [nope, no generic methods]
- Otherwise, if the namespace-or-type-name appears within a type declaration, then for each instance type T (§10.3.1), starting with the instance type of that type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):
- If
Kis zero and the declaration ofTincludes a type parameter with nameI, then the namespace-or-type-name refers to that type parameter. [Nope]- Otherwise, if the namespace-or-type-name appears within the body of the type declaration, and
Tor any of its base types contain a nested accessible type having nameIandKtype parameters, then the namespace-or-type-name refers to that type constructed with the given type arguments. [Bingo!]- If the previous steps were unsuccessful then, for each namespace
N, starting with the namespace in which the namespace-or-type-name occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:
- If
Kis zero andIis the name of a namespace inN, then... [Yes, that would succeed]
So that final bullet point is what picks up the Sparta class if the first bullet doesn't find anything... but when the base class Place defines an interface Sparta, it gets found before we consider the Sparta class.
Note that if you make the nested type Place.Sparta a class rather than an interface, it still compiles and returns false - but the compiler issues a warning because it knows that an instance of Sparta will never be an instance of the class Place.Sparta. Likewise if you keep Place.Sparta an interface but make the Sparta class sealed, you'll get a warning because no Sparta instance could ever implement the interface.
When resolving a name to its value the "closeness" of the definition is used to resolve ambiguities. Whatever definition is "closest" is the one that is chosen.
The interface Sparta is defined within a base class. The class Sparta is defined in the containing namespace. Things defined within a base class are "closer" than things defined in the same namespace.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With