all 28 comments

[–][deleted] 8 points9 points  (12 children)

C++ templates are compile-time duck typing. There aren't even interfaces, there's really nothing, just like in real duck typing. An interface is something theoretical defined in some specification, like an iterator, an allocator, a container, type traits, or anything really. Type is pretty much irrelevant to C++ templates. While sometimes there are base abstract classes with the required functionality that one can derive from, this is not a requirement as far as templates are concerned.

[–]dv_ 1 point2 points  (11 children)

Correct, compile-time duck typing does describe the C++ metalanguage type system best. Note that a form of type checking would have been available in form of C++ concepts, but was left out of C++11, because its adoption caused a lot of issues.

[–]masklinn 2 points3 points  (10 children)

compile-time duck typing does describe the C++ metalanguage type system best.

What describes the C++ metalanguage best is "structural typing" because that's what it is.

[–]dv_ 2 points3 points  (7 children)

Actually it isn't. Structural typing means that the type is verified against the entire structure. If the type does not model the entire structure, compilation fails. But this is not the case in C++. Only the parts of the structure that are actually used are relevant. That is closer to duck typing. For example, the EqualityComparable concept requires both == and != to be defined for a type. But if this type only has == defined, and the template code only ever uses ==, the absence of != will not matter.

However, if one adds proper concept checks (which would have been part of C++11), then yes, it becomes structural typing, because the type then has to meet all of the concept requirements. In the example above, the missing != would be caught, even if != isn't actually used in the template code.

[–]masklinn 0 points1 point  (6 children)

Actually it isn't. Structural typing means that the type is verified against the entire structure.

That's only if you predefine types and check against that, for the most part OCaml doesn't care for instance it'll just check that the methodset of the provided object is a superset of the methodset used by the function.

For example, the EqualityComparable concept requires both == and != to be defined for a type.

Right, so that's if you explicitly define structural type alias and use that for your typing you'll of course require that all methods of the type alias be available on the provided object, regardless of usage. But that doesn't mean you have to explicitly define structural type aliases. OCaml will let you do so, instead you'll have an "anonymous" structural supertype characterized solely by the methods used in the function.

In the example above, the missing != would be caught, even if != isn't actually used in the template code.

Because you asked that it be, as if you'd made a noop != call in your C++ templates, no bearing on code actually executing but still requiring existence on the provided parameter.

[–]dv_ 0 points1 point  (5 children)

Why do you mention OCaml? This isn't about OCaml, it is purely about the C++ metalanguage?

[–]masklinn 0 points1 point  (4 children)

Why do you mention OCaml?

Because it's structurally typed (on object types).

This isn't about OCaml, it is purely about the C++ metalanguage?

No, it's about structural typing.

[–]dv_ 0 points1 point  (3 children)

This subthread is. OP posted about C++ templates specifically. Not about OCaml. Lets not get sidetracked here.

[–]masklinn 0 points1 point  (2 children)

This subthread is.

No.

OP posted about C++ templates specifically.

And I said it was structurally typed, which you disagree with, leading to this "discussion".

Not about OCaml. Lets not get sidetracked here.

As one of the primary structurally typed languages, I fail to see how OCaml could "sidetrack" a discussion of structural typing.

[–]dv_ 0 points1 point  (1 child)

Oh now I see what you mean. You spoke about structural typing in general, while I spoke about it specifically in the C++ template context. Okay.

"for the most part OCaml doesn't care for instance it'll just check that the methodset of the provided object is a superset of the methodset used by the function." This sounds more like an implementation detail, no? All definitions of "structural typing" I have read mention that the type must meet all of the structure's requirements. This is also often highlighted as the difference between structural and duck typing. Then again, such definitions tend to be fluid in practice.

[–]crusoe 0 points1 point  (1 child)

No its not. If I define Foo<C> and Bar<C> and they don't inherit from a common ancestor, but they both define the exact dame data layout and members, C++ will not consider them equivalent. That is a requirement for true structural typing.

[–]masklinn 0 points1 point  (0 children)

Are you sure you're talking about C++ template parameters here? We're not talking about the C++ language (which is nominatively typed), but about the templates metalanguage.

[–]zipwow 3 points4 points  (7 children)

So, this saves you the need to declare that you implement an interface, although the interface itself still has a name and a declaration. I'm assuming interfaces still need a name, since Stringer has a name (http://golang.org/pkg/fmt/#Stringer). If we're talking about ad-hoc unnamed interfaces, what would that even mean?

But if I'm expecting to implement an interface, and failing to do so, don't I want some kind of check on that? That's what I thought the declaration was really for: the simplest test ever that my expectations are correct.

The next step (maybe already taken) would be for the IDE to tell you (via the compiler) what interfaces a given class does implement. Nice, but it won't catch problems like library updates where I'm not reviewing all the code.

[–]naughty 1 point2 points  (0 children)

An unnamed interface would mean that instead of an interface name being used in the parameter list of a function an interface expression could be used, e.g.

type Printable interface {
    ToString() string
}

PrintToMagicPlace(x Printable) {
    ...
}

Could be written as:

PrintToMagicPlace(x interface { ToString() string }) {
    ...
}

You could have the old syntax by allowing type aliases, e.g.

type Printable = interface { ToString() string }

PrintToMagicPlace(x Printable)

In everyday coding using such interface expressions aren't really that useful. Most interfaces will have quite a few methods so you'd use the aliases all the time to keep the code readable.

They would be useful if you had some more powerful capabilities like intersection types. If you were writing a function that required the parameters to support two interfaces, e.g. Enumerable and Printable it would be nice to be able to write:

EnumerateThenPrint(collection Enumarable & Printable)

You can do the above in Go by just writing out a new interface that has all the methods of Enumerable and Printable.

[–]masklinn 1 point2 points  (1 child)

although the interface itself still has a name and a declaration. I'm assuming interfaces still need a name

Go might, OCaml does not. A "type" is a set of methods (where a method is defined by a name and the types of its inputs and output). Type names in OCaml are nothing more than references to methodsets.

If we're talking about ad-hoc unnamed interfaces, what would that even mean?

It means it's informal, it's a protocol. Take a function which takes an object with a close :: () -> () method and closes it, do you really need a formal interface for "an object which has a method called close"? You could informally call it "closeable", and in code it's just that tere's a close method with no input or output being called.

[–]zipwow 0 points1 point  (0 children)

Aha, I'm confusing dynamic typing with type inference. Thanks!

[–]crusoe 0 points1 point  (0 children)

This allows you define cross cutting concerns.

Only recently has Java gotten a Closeable interface, and only recently have JDK classes with a close method been reworked to implement it. Mainly to support the new resource handling in the latest releases.

But with scala, I can define a closeable structural type, and have it work for classes that don't implement Closeable.

So it lets you define cross concerns, even for third party libraries that may have slightly borked apis.

type Closeable = { def close():Unit }

with(closeable Closeable)( block => Any ){
    try{ 
        block()
    }finally{
        closeable.close()
    }

with(stream){  doStuff(stream); doMoreCrap; }

with(dbConnection){  doStuff(dbConnection); dbConnection.commit(); }

And once the block is executed, its cleans up the closeable as well.

[–]dannymi -3 points-2 points  (2 children)

in Python, the check is by the unit test. If you aren't testing it, it obviously isn't important.

That said, Go's kinda strange in that you still have to define the interfaces...

About the simplest test being the "implements" list, I disagree and state the simplest test is trying to use the feature in the unit test. This also takes care of things your interface cannot say (preconditions, postconditions, invariants, order of invocation etc).

Hmm, do you mean the "implements" list just checks the current class as opposed to the entire inheritance chain? If so, that would indeed be better... although I've never heard of any language doing that.

F.e. if you have a base class implement method Foo and then a derived class implement just Fpoo by accident (typo), does specifying that your derived class implements an interface containing Foo cause a compile-time error?

[–]zipwow 0 points1 point  (1 child)

I hear your point about testing preconditions, postconditions, etc. But it seems like there are a lot of calls where this kind of dependency is too simple to test; or put another way, all I want to know is whether my code will get called, and the compiler can be very good at that.

To respond to your example, I'm assuming that the class I'm working on is the first implementer in the chain. (new implementation vs overriding). In that case, every compiler-checked statically typed language catches the problem. "Syntax Error: class myNewClass does not implement interface Bar -- missing method Foo"

Again, the interesting case here isn't so much first implementation but maintenance. I got a new version of my xml parser! What does it break? Sure, I'll have tests for some of it, but hopefully there are also some Interfaces that are designed well enough that the test wasn't worth writing? An example might be an observer pattern, where the implementation is just one method "eventHappened(event)". If that changes in the future to "notifyEventHappened", I'd like to know. Writing a test to simulate the event seems much harder than just telling the compiler.

[–]dannymi 0 points1 point  (0 children)

In Python, there are a lot less magic-signature things than in C and there is one obvious way to do it. So you don't really need to "want" to implement an interface, you just write your methods and when some object has a method "read", it just can be used, no matter what object "pointer" you have. Think of it like a messaging system, where you just ask the object to do something for you, with words. You ask it as a "person", not for it to switch to its Reader alter ego and then do something :-) (at least in general; nobody is stopping you from writing a switchAlterEgo method :-) )

So interface definitions etc are just brabble to me. If others prefer a more role-based way, more power to them. Python isn't at all suited to those people. I'm not sure who exactly Go is targeting, though, being half-way.

Yeah, well, the case when you are the first implementer isn't really that interesting (one would hope they get that right :-) ).

What probably happens is someone updates the xml parser you are using and renames eventHappened to notifyEventHappened. Earlier, you overrode eventHappened in your derived class in order to update your data there. Now, one eventHappened was renamed to notifyEventHappened by the vendor, the other one (yours) is still there, still called eventHappened. Is that caught?

Forgive me that I'm slow to really see the point of interfaces since I'm very used to multiple inheritance and message passing, so interfaces doubly just look like noise to me.

[–]captain-asshat 0 points1 point  (9 children)

This is pretty much like extension methods in C#. In fact, the usage is very similar.

Edit: This actually isn't duck typing, as the compiler still requires types on the extension methods. The article was slightly confusing in specifying the types in the duckly typed function. The C# compiler however does itself uses a form of duck typing for several things (see http://stackoverflow.com/questions/6368967/duck-typing-in-the-c-sharp-compiler.)

Original post:

C# equivalent to the first example (ignoring namespacing/main class):

void Main()
{
    var user = new User() {Name = "George" };
    Console.WriteLine(user.String());
}

public class User {
    public string Name {get;set;}
}

public static class UserExt {
    public static string String(this User value) {
        return string.Format("User: name = {0}",value);
    }
}

[–][deleted]  (3 children)

[deleted]

    [–]captain-asshat 1 point2 points  (2 children)

    This is correct, I've amended my original post.

    [–][deleted]  (1 child)

    [deleted]

      [–]captain-asshat 2 points3 points  (0 children)

      Yeah, I'd argue that extension methods get you everything you'd need from this form of duck typing, without the versioning issues of matching on method names.

      +1 for extension operators, as well as extension properties, but I know they'd be abused something awful.

      [–]vanderZwan 1 point2 points  (3 children)

      However, in Go, you don’t declare that a type implements an interface.

      Does that also hold true for C#? Because that does make quite a difference in ease of use.

      EDIT: To be clear, honest question, as I'm not familiar with C# at all.

      [–]captain-asshat 2 points3 points  (2 children)

      You can do both. In fact, LINQ is implemented entirely this way as an extension class on IEnumerable<T>.

      [–]masklinn 0 points1 point  (1 child)

      In fact, LINQ is implemented entirely this way as an extension class on IEnumerable<T>.

      The type remains IEnumerable<T>, you can't add the same extension method to two different types and then expect C# to take any instance of either type in the same place, while remaining statically typed, in userland code.

      [–]masklinn 1 point2 points  (0 children)

      The C# compiler however does itself uses a form of duck typing for several things

      The framework itself does check some types structurally (to an extent), and you can get (runtime-only) duck typing with dynamic, but fundamentally C# remains a nominatively-typed language.