Author | Message | Time |
---|---|---|
Imperceptus | I keep seeing references on msdn that some objects have interfaces, what are they good for? | September 25, 2009, 6:57 PM |
Camel | Not sure if the mapping is 1:1, but in Java, an interface is one of the three base types (the others being classes and primitives). It is similar to a class in that it defines method signatures, but it does not define method bodies. You can not instantiate an interface. Implementing an interface is similar to extension (aka inheritance), except that you're required to implement the methods defined. By contrast, when you extends a class, you may override non-final method behavior if you choose. Objects of classes that implement an interface can be (implicitly or otherwise) cast to the interface's type. This is particularly useful if you have two classes that share common behavior, but are not have a super/sub-type relationship. For example, Jack and Jill might both be FictionalCharacters, but Jack does not extend Jill. Defining an inteface FictionalCharacter that Jack and Jill both implement allows reuse of code that operates on all FictionalCharacters. [tt]interface FictionalCharacter { void goUpTheHill(); } class Jack implements FictionalCharacter { void goUpTheHill() { ... } }[/tt] HTH | September 26, 2009, 2:43 AM |
PiaNKA | It should also be noted that interfaces do not have state. Nice example by the way :P | September 27, 2009, 8:04 PM |
Imperceptus | What do you mean by they are stateless? They have no constructor? | September 29, 2009, 3:19 PM |
PiaNKA | It is true that they have no constructor. However, I meant that interfaces may not contain variables [except for constants, but these are usually inlined at compile time]. For instance in Camel's example we might want to store the age of Jack and Jill. To do so we cannot just put an int into the interface. In that situation, it would be better to use an abstract class. | September 30, 2009, 5:20 PM |
Myndfyr | Interfaces also can contain properties, but they don't contain the implementation. Ultimately, interfaces are one of the ways to prevent yourself from being tied to a specific implementation (the other being an inheritence tree). In that way, they're great for defining points of extensibility. Take BN#'s ICommandQueue interface for example: [quote]Implements an outgoing command queue, which allows the client to delay, filter, or reorder messages that are waiting to be sent to prevent flooding. The default implementation does not delay or reorder messages.[/quote] BN# allows a programmer using BN# to create a bot to change the way that messages are sent. By default, messages go through the DefaultCommandQueue, which lets a BattleNetClient know that a message is ready to be sent as soon as it is queued up. JinxBot, on the other hand, implements a message queue using a timer. However, using this interface, developers can replace the standard command queue with something custom - for instance, a moderation plugin may replace the standard queue to prioritize /ban and /kick commands, or to obey the Priority parameter (which is ignored by default in the default and JinxBot implementations). So that's an example of how interfaces are used in an application or an API. Interfaces tend to be preferred for methods of extensibility because they are multiply-inherited (whereas classes can only derive from a single immediate parent class). Camel is correct in his analysis, though .NET supports five base types (classes, structs, enums, delegates, and interfaces). | September 30, 2009, 10:32 PM |
Imperceptus | Can you use multiple interfaces at the same level within an object? | October 2, 2009, 9:29 PM |
Myndfyr | [quote author=Imperceptus link=topic=18071.msg183448#msg183448 date=1254518960] Can you use multiple interfaces at the same level within an object? [/quote] Yes. That's what makes them more interesting than classes. The primary difference between classes an interfaces is their semantic meaning. A "class" has "behaviors" (methods) and "state" (data fields) attached to it. An interface is really a contract that a specific class implements a specific behavior only. An example illustrating the difference between C#/Java's implementation of interfaces and C++'s implementation of multiple inheritence might be in order. Consider this C++ code: [code] class A { public: int foo; void setFoo(int value) { foo = value; } } class B { public: int foo; virtual void bar() = 0; } class C : public A, public B { } [/code] Now, in this case, C has two copies of "foo" - one attached to the vtable of its A and one attached to B. So to access its value, you have to qualify which one you're addressing: [code] C* item = new C; item->foo = 10; // compiler error (dynamic_cast<B>(item))->foo = 10; // now C's copy of B's foo is 10, but A's foo is still 0. [/code] Java and C# avoid this by only allowing classes to have a single inheritance chain for classes - which means there isn't any ability of such a data collision to take place. However, since the semantic meaning of an interface is to define behaviors, you can define any number of interfaces that have the same method names: [code] // Java public interface A { int getFoo(); } public interface B { int getFoo(); void setFoo(int value); } public interface C { void setFoo(int value); } public class ABC implements A, B, C { private int _foo; public int getFoo() { return _foo; } public void setFoo() { _foo = value; } } [/code] This assumes that the semantic meanings of "getFoo" and "setFoo" are the same, but the implementing class only needs to implement the behaviors once. (A little-known and rarely-used feature of) C# actually takes it a step further and allows you to explicitly implement an interface's behavior per-interface. The theory is that you'd only call that method if you have a type reference to the interface, otherwise it won't be part of the class's actual use. For instance, consider I used the same A, B, and C interfaces from above: [code] // C# public class ABC : A, B, C { private int _foo, _bar; public int getFoo() { return _foo; } public void setFoo(int value) { _foo = value; } int B.getFoo() { return _bar; } void B.setFoo(int value) { _bar = value; } } [/code] If you have C# code that does this: [code] ABC obj = new ABC(); obj.setFoo(10); [/code] The internal variable _foo will equal 10. But, if you have this: [code]B obj = new ABC(); obj.setFoo(10); [/code] The _bar variable will equal 10. Explicitly-implemented interfaces are rarely useful, but they have their occasional value. In 8 years, though, I think I've only used them maybe 3 or 4 times. Your mileage may vary. :) | October 4, 2009, 12:22 AM |
Camel | [quote author=MyndFyre link=topic=18071.msg183436#msg183436 date=1254349944] Camel is correct in his analysis, though .NET supports five base types (classes, structs, enums, delegates, and interfaces). [/quote] In Java, enums are actually classes (which extend java.lang.Enum). Is it the same in .NET? It happens somewhat under the hood (the 'enum' keyword replaces the 'class' keyword), but it's still pretty clear what's happening there. Structs and delegates simply don't exist there; structs are believed by the Java ideology to be poor design, and delegate functionality can be achieved by constructing an anonymous interface. [tt] interface FictionalCharacter { void goUpTheHill(); } void main() { FictionalCharacter jack = new FictionalCharacter() { void goUpTheHill() { ... } }; } [/tt] | October 5, 2009, 5:48 PM |
Imperceptus | nice explanation ive found structs to always bite me in the ass down the road myself. I do like how vb.net handles delegates though. | October 6, 2009, 2:22 PM |
Myndfyr | [quote author=Camel link=topic=18071.msg183463#msg183463 date=1254764906] In Java, enums are actually classes (which extend java.lang.Enum). Is it the same in .NET? It happens somewhat under the hood (the 'enum' keyword replaces the 'class' keyword), but it's still pretty clear what's happening there. [/quote] Everything in .NET *always* ultimately extends System.Object - even type primitives and structs in .NET. The CLR treats them semantically different, though. * Classes are always allocated on the heap and have reference behavior; unless explicitly stated, they always derive from System.Object. * Structures inherit from System.ValueType (a descendant of System.Object) and are always allocated on the stack and have copying behavior. * Enums inherit from System.Enum (a descendant of System.ValueType) and are allocated on the stack, but are treated as numeric constants or literals (they are carried around as integers - even when compiled - and do not hold type information). * Interfaces can be implemented by either classes or structures. * Delegates derive from System.MulticastDelegate (then Delegate, then Object) and contain a function pointer and the "this" object. So that was a long way to answer your question: no, it doesn't seem like they're the same. | October 6, 2009, 8:40 PM |
Imperceptus | I swear I learn more on these forums then I do from books | October 6, 2009, 9:51 PM |
Camel | As a Java guy, that sounds awfully over-complicated for not much benefit. I'm sure that to you the Java way seems over-simplified, though. ;) | October 6, 2009, 10:24 PM |
Myndfyr | [quote author=Camel link=topic=18071.msg183487#msg183487 date=1254867864] As a Java guy, that sounds awfully over-complicated for not much benefit. I'm sure that to you the Java way seems over-simplified, though. ;) [/quote] I think there are lots of good reasons for allowing stack-bound variables (for you they're primitives) to have functions. Most specifically, they don't require any heap allocation or garbage collection - so if I call: [code] int x = 5; Console.WriteLine(x.ToString()); [/code] My compiler isn't doing this: [code] int x = 5; Integer @__x = new Integer(x); Console.WriteLine(@__x.ToString()); [/code] (Of course when I started Java programming, you didn't get that automatic conversion, so it was even more annoying). ;-) The advantage there is obviously less fragmentation that the garbage collector has to deal with. There are additional benefits for the not-so-faint-of-heart as well, like the use of pointers to point to stack memory. :) | October 7, 2009, 4:09 AM |
Camel | Java doesn't auto-box the int either; it would use [tt]static String java.lang.Integer.toString(int)[/tt]. Auto-boxing only happens if you cast a primitive to a super-primitive. And, for the record, this specific example would never be an issue anyways, because System.out.println(int) is one of the overloads. Additionally, the + operator for Strings and String.concat() have (int) overloads. | October 7, 2009, 5:08 PM |
Imperceptus | What is this Auto-Boxing? | October 7, 2009, 9:20 PM |
Myndfyr | [quote author=Imperceptus link=topic=18071.msg183494#msg183494 date=1254950456] What is this Auto-Boxing? [/quote] Autoboxing is a Java feature that works like this: [code] // input code: static void main(String[] args) { int x = 5; int y = 10; doStuff(x, y); } static void doStuff(Integer x, Integer y) { System.out.println(x.toString() + ", " + y.toString()); } [/code] The effective generated code is: [code] static void main(String[] args) { int x = 5; int y = 10; Integer @__x = new Integer(x); Integer @__y = new Integer(y); doStuff(@__x, @__y); } static void doStuff(Integer x, Integer y) { System.out.println(x.toString() + ", " + y.toString()); } [/code] In Java, the primitive "int" doesn't semantically mean the same as "Integer", whereas in .NET, there is no distinction between a primitive and the actual structure. The structure for "int" is always System.Int32. C# creates a "type alias" called "int" for System.Int32 (VB.NET's is "Integer"), it's all the same. There's autoboxing in .NET, but it happens when you assign a value-type to Object: [code] int x = 5; object o = x; // the value 5 is now on the heap int y = (int)o; // the value from the heap is unboxed. [/code] | October 8, 2009, 2:32 AM |
Camel | The converse is also true; if you cast a java.lang.Integer to an int, the compiler will auto-unbox it with a call to .intValue(). [quote author=MyndFyre link=topic=18071.msg183496#msg183496 date=1254969160] There's autoboxing in .NET, but it happens when you assign a value-type to Object: [code] int x = 5; object o = x; // the value 5 is now on the heap int y = (int)o; // the value from the heap is unboxed. [/code] [/quote] Does that count as auto-(un?)boxing? Correct me if I'm wrong, but it looks like that code is not pulling something out of an "object" box, but rather just casting the same reference as different types. In the Java sample, java.lang.Integer is a box that wraps the primitive int, which otherwise could not be 'null'. | October 8, 2009, 2:47 PM |
Myndfyr | [quote author=Camel link=topic=18071.msg183500#msg183500 date=1255013244] Does that count as auto-(un?)boxing? Correct me if I'm wrong, but it looks like that code is not pulling something out of an "object" box, but rather just casting the same reference as different types. In the Java sample, java.lang.Integer is a box that wraps the primitive int, which otherwise could not be 'null'. [/quote] That's boxing and unboxing, yes. But boxing in .NET is generally considered to be bad practice since it's generally unnecessary. You wouldn't do this in Java: [code] int x = 5; Integer y = x; Object z = y; int fooBar = (int)((Integer)z); [/code] That would be silly, but is effectively what I'm doing in that code. There are very rarely reasons to store an integer on the heap unless it's part of another object. | October 9, 2009, 5:59 AM |
Camel | [quote author=MyndFyre link=topic=18071.msg183505#msg183505 date=1255067944] There are very rarely reasons to store an integer on the heap unless it's part of another object. [/quote] You can't put the primitive in a class? | October 9, 2009, 3:46 PM |
Myndfyr | [quote author=Camel link=topic=18071.msg183508#msg183508 date=1255103166] [quote author=MyndFyre link=topic=18071.msg183505#msg183505 date=1255067944] There are very rarely reasons to store an integer on the heap unless it's part of another object. [/quote] You can't put the primitive in a class? [/quote] You can: [quote author=MyndFyre link=topic=18071.msg183496#msg183496 date=1254969160] There's autoboxing in .NET, but it happens when you assign a value-type to Object: [code] int x = 5; object o = x; // the value 5 is now on the heap int y = (int)o; // the value from the heap is unboxed. [/code] [/quote] Are we talking about that or this: [code] public class Foo { public int Bar; } [/code] Both are valid. The latter is used regularly. The former is what I was referring to. When you say "object o = 5;" that's "boxing" in .NET and it's generally considered bad practice since you don't need to put an integer on the heap. | October 9, 2009, 6:52 PM |
Camel | If you try to set an [tt]int[/tt] to [tt]null[/tt], to you get an NPE? I'm going to assume the answer is yes, since I believe you said they are stack-bound which means they are not objects (even if the language allows you to operate on them as if they were). So, then, let's say you have a method that returns an integer most of the time, but can sometimes returns null -- but that does not indicate an error, and thus doesn't warrant throwing an exception. Does the return type of that method have to be Object, then? How does a naive caller know that the method can only return ints, if there is no super-primitive? | October 11, 2009, 2:41 AM |
Myndfyr | [quote author=Camel link=topic=18071.msg183517#msg183517 date=1255228873] If you try to set an [tt]int[/tt] to [tt]null[/tt], to you get an NPE? I'm going to assume the answer is yes, since I believe you said they are stack-bound which means they are not objects (even if the language allows you to operate on them as if they were). So, then, let's say you have a method that returns an integer most of the time, but can sometimes returns null -- but that does not indicate an error, and thus doesn't warrant throwing an exception. Does the return type of that method have to be Object, then? How does a naive caller know that the method can only return ints, if there is no super-primitive? [/quote] You can't set an [tt]int[/tt] to null. You get a compiler error. If you do this: [code] object o = 5; o = null; [/code] You set the object reference [tt]o[/tt] to null, which is workable because [tt]o[/tt] is bound to type [tt]object[/tt], not [tt]int[/tt]. .NET 2.0 introduced a concept of "nullable types" that utilize a generic: [code] public struct Nullable<T> where T : struct { public bool HasValue { get; } public T Value { get; } } [/code] That structure generally has compiler support within languages to do implicit casting and whatnot; in C#, it's represented by the ? operator. So your method signature might look like this: [code] public static int? DoSomething(int v) { ... } [/code] However, if the return type was "int" the caller knows that the method will only return int. There is no such thing as a null int - only a null int?. Value-types still function as objects, though; they have vtables, it's just that the vtables belong to the owning class, not to a specific instance on the stack (although even that is moderately true of heap objects). To put it another way: All .NET heap objects are stored on the stack as pointers to their memory datum. So assuming I have a string off in memory, what actually is living on the stack is a pointer to that memory - probably to an integer specifying how long the string is. One machine word previous to that reference is a pointer to the object's "runtime type handle" which then provides me access to its vtable. Stack-bound objects - structures or otherwise - don't have this. So, I can cast between them (if my language allows). The following isn't valid C#, but it conveys my meaning. Assuming I have this struct: [code] public struct Point { int x; int y; override string ToString() { return "(" + x + ", " + y + ")"; } } [/code] Assume the following code is valid (the compiler wouldn't let me do it): [code] Point p = new Point { x = 5, y = 10 }; int x = p; Console.WriteLine(x.ToString()); [/code] Off the cuff, I'd say that the output would be [tt]5[/tt]. The correct vtable is bound at compile-time based on the type determined by the owning type. HOWEVER, if I wrote this code (this will compile and execute correctly): [code] Point p = new Point { x = 5, y = 10 }; object x = p; Console.WriteLine(x.ToString()); [/code] The output would be the correct [tt](5, 10)[/tt] because the correct type is stored during the boxing procedure. | October 11, 2009, 8:11 PM |
Camel | Ah, I see. Because there are other stack-bound types besides primitives, it's not sufficient to simply create super-primitives in .NET. IMO, it's worth the trivial performance hit to just put everything on the heap to save the language from becoming cryptic. Objects and types that have obvious life-cycles don't need to go through the garbage collector anyways. For example, in the following: [code] int getValue() { Integer x = new Integer(4); return x.intValue(); } [/code] x would be allocated on the heap, but would be destroyed an freed at the end of the method. Of course, if you actually wrote the above code, hotspot would never allocate the integer at all; it would optimize it out. It'd also probably inline the method. | October 13, 2009, 8:03 PM |
Myndfyr | [quote author=Camel link=topic=18071.msg183542#msg183542 date=1255464235] IMO, it's worth the trivial performance hit to just put everything on the heap to save the language from becoming cryptic. [/quote] It's interesting that every Java programmer to whom I've explained the distinction between stack types and heap types in .NET has followed by criticizing this as cryptic, yet I've never seen that "problem" be experienced.... | October 15, 2009, 1:46 PM |
Imperceptus | For the record most of what yall have discussed about the heap in the last few responses is very cryptic to me. However my level of experience is novice compared to yall. | October 15, 2009, 2:16 PM |
Camel | [quote author=MyndFyre link=topic=18071.msg183556#msg183556 date=1255614388] [quote author=Camel link=topic=18071.msg183542#msg183542 date=1255464235] IMO, it's worth the trivial performance hit to just put everything on the heap to save the language from becoming cryptic. [/quote] It's interesting that every Java programmer to whom I've explained the distinction between stack types and heap types in .NET has followed by criticizing this as cryptic, yet I've never seen that "problem" be experienced.... [/quote] What's the practical advantage of doing it that way? I see several drawbacks, but the only advantage I can see is a trivial performance boost, assuming the developer knows how to take advantage of it. It's not intuitive; the concept of a modern language reverting to the ways of C (where you' have to stop and look at the type declaration to figure out if something lives on the stack or the heap) irritates me. If heap performance is such a big concern, why would you use such a high level language in the first place? [edit] I should also point out that I'm not opposed to the jitter using structs and heap-bound types at runtime. I just think that you shouldn't be expected to know the difference to write code. | October 15, 2009, 4:28 PM |
Imperceptus | Camel, I for one don't know the difference. But I do wish I do understand it a more in depth level. | October 20, 2009, 7:48 PM |
Myndfyr | [quote author=Camel link=topic=18071.msg183558#msg183558 date=1255624103] [edit] I should also point out that I'm not opposed to the jitter using structs and heap-bound types at runtime. I just think that you shouldn't be expected to know the difference to write code. [/quote] You aren't expected to know the difference. I don't understand why it keeps coming up. 99% of the people I've worked with have never declared a struct. There are specific reasons to do it, and most business applications don't need them. Getting pointers to structures, for instance, is a huge optimization (because the garbage collector doesn't have to work around them). But again - this is a very unusual situation and most people don't have to do it. There's a distinction between *having* to do something and *being able* to do something. | October 20, 2009, 8:18 PM |
Camel | A the GC would never have to worry about the equivalent object to a stack-bound struct, because its scope will end within the method, and the GC will therefore not have to 'watch' its life-cycle. | October 21, 2009, 5:10 PM |
Myndfyr | [quote author=Camel link=topic=18071.msg183572#msg183572 date=1256145000] A the GC would never have to worry about the equivalent object to a stack-bound struct, because its scope will end within the method, and the GC will therefore not have to 'watch' its life-cycle. [/quote] Precisely why it's advantageous. If I create an array of heap-bound objects and then take a pointer to it, the garbage collector has to "pin" the objects so that they're not relocated during compaction. If I instead create an array of stack-bound objects, since the stack is not subject to the garbage collector, I can take pointers to them as long as I want without regard or worry about its impact on the GC. | October 21, 2009, 8:19 PM |
Camel | I don't think you understood what I'm saying at all. If you create an object, and the jitter knows that there's no code path where it can have remote references at the end of its declarative scope, it will create machine code that destroys and deallocates it at the end of its scope instead of sending it to the collector for reference monitoring. In the example: [code] int[] getInts() { List<Integer> ints = new ArrayList<Integer>(100); for(int x = 0; x < 100; x++) ints.add(new Integer(x)); return ints.toArray(); } [/code] the object referenced by ints will never make it to the collector. The limitation on this enhancement is the same limitation that you'd inherently get with stack-bound data anyways: it can't leave its declarative scope. That completely invalidates any argument for performance gain by putting non-references/primitives in the stack that I can think of. [edit] Of course, if you pass the object to overridable/external code, the jitter won't be able to perform the enhancement; but I think it's unlikely that someone would choose such a pattern in a time-critical segment of code. | October 23, 2009, 7:57 PM |
-MichaeL- | I am trying to make sense of this, It is better to pass things as whatever they are declared as rather then passing them as just an object? For example in C# [code] public void main() { string greeting = "hello world"; } public void DisplayGreeting(string greeting) { debug.print(greeting); } [/code] would be better to do then [code] public void main() { string greeting = "hello world"; } public void DisplayGreeting(object greeting) { debug.print(greeting.tostring()); } [/code] | January 17, 2010, 4:48 AM |
Myndfyr | It's effectively the same thing when dealing with reference types (like string). When dealing with value types (like int), there's an operation called "boxing" and "unboxing" that has to happen. You can look up info about boxing/unboxing. | January 18, 2010, 4:24 AM |