Re: Go-lang like interface
This thread is a bit dusty, but I just want to mention, that I made some improvements to andrea's implementation, in case somebody is still interested in interfaces like this, while vtrefs are still unimplemented. Mainly I fixed it(previously the generated AST was invalid) and added a way to export interfaces. I've already made a [pull request](https://github.com/andreaferretti/interfaced/pull/1).
Re: Go-lang like interface
Go ahead and publish it however you want. I mean this is some form of publishing, it is just not a git repository. I don't claim any patents here, I published it so it could get spread around the world. If you want to, you could add a link that says that you got inspired by this thread, then I might add a link to your version in the initial post.
Re: Go-lang like interface
A minor minor variant that works with `var` parameters instead of `ptr`: import macros macro implementInterface(interfaceName: typed) : untyped = let interfaceNameStr = $interfaceName.symbol vtableSymbol = interfaceName.symbol.getImpl[2][2][1][1][0] vtableRecordList = vtableSymbol.symbol.getImpl[2][2] let objectConstructor = nnkObjConstr.newTree(vtableSymbol) for identDefs in vtableRecordList: let methodName = identDefs[0] params = identDefs[1][0] lambdaBody = quote do: cast[var T](this).`methodName`() call = lambdaBody[0] for i in 2 ..< len(params): let param = params[i] param.expectKind(nnkIdentDefs) for j in 0 .. len(param) - 3: call.add param[j] # leave out () when not needed if call.len == 1: lambdaBody[0] = call[0] methodName.expectKind nnkIdent objectConstructor.add nnkExprColonExpr.newTree( methodName, nnkLambda.newTree( newEmptyNode(),newEmptyNode(),newEmptyNode(), params.copy, newEmptyNode(),newEmptyNode(), lambdaBody ) ) let getVtableReturnStatement = nnkReturnStmt.newTree(newCall("addr", newIdentNode("theVtable"))) globalVtableIdent = newIdentNode("theVtable") getVtableProcIdent = newIdentNode("get" & interfaceNameStr & "Vtable") getVtableProcDeclaration = quote do: proc `getVtableProcIdent`[T](): ptr BananasVtable = var `globalVtableIdent` {.global.} = `objectConstructor` `getVtableReturnStatement` result = newStmtList() result.add getVtableProcDeclaration let castIdent = newIdentNode("to" & $interfaceName.symbol) result.add quote do: converter `castIdent`[T](this: ptr T) : `interfaceName` = `interfaceName`( objet : this, vtable : `getVtableProcIdent`[T]() ) result.add quote do: converter `castIdent`[T](this: var T) : `interfaceName` = `interfaceName`( objet : this.addr, vtable : `getVtableProcIdent`[T]() ) result.add quote do: converter `castIdent`(this: `interfaceName`): `interfaceName` = this when defined(interfacedebug): echo result.repr macro createInterface*(name : untyped, methods : untyped) : untyped = name.expectKind nnkIdent let nameStr = $name.ident vtableRecordList = nnkRecList.newTree vtableIdent = newIdentNode(nameStr & "Vtable") vtableTypeDef = nnkTypeSection.newTree( nnkTypeDef.newTree( vtableIdent, newEmptyNode(), nnkObjectTy.newTree( newEmptyNode(), newEmptyNode(), vtableRecordList ) ) ) var newMethods = newSeq[NimNode]() for meth in methods: meth.expectKind(nnkProcDef) let methodIdent = meth[0] params = meth[3] thisParam = params[1] thisIdent = thisParam[0] thisType = thisParam[1] if thisType != name: error thisType.repr & " != " & name.repr let vtableEntryParams = params.copy vtableEntryParams[1][1] = newIdentNode("pointer") vtableRecordList.add( nnkIdentDefs.newTree( methodIdent, nnkProcTy.newTree( vtableEntryParams, newEmptyNode(), ), newEmptyNode() ) ) let call = nnkCall.newTree( nnkDotExpr.newTree( nnkDotExpr.newTree(thisIdent, newIdentNode("vtable")), methodIdent ), nnkDotExpr.newTree( thisIdent, newIdentNode("objet") ), ) for i in 2 ..< len(params): let param = params[i] param.expectKind(nnkIdentDefs) for j in 0 .. len(param) - 3: call.add param[j] meth[6] = nnkStmtList.newTree(call) newMethods.add(meth) result = newStmtList() result.add(vtableTypeDef) result.add quote do: type `name` = object objet : pointer vtable: ptr `vtableIdent` for meth in newMethods: result.add meth result.add newCall(bindSym"implementInterface", name) when defined(interfacedebug): echo result.repr Usage: import interfacemacros type MyBananas = object a,b : int OtherBananas = object foo,bar: int proc foo(banan : var MyBananas) : int = banan.a + banan.b proc bar(banan : var MyBananas) : int = banan.a * bana
Re: Go-lang like interface
@Udiknedormin What you call inheritance I would, if I do implement it, rather do as embedding. createInterface BeautyGenerator: HealthGenerator EnergyGenerator proc genBeauty(g: BeautyGenerator): Beauty You can se Go type embedding for example.This would create implicit conversions to HealthGenerator and EnergyGenerator. I think it's possible with not too much effort, which doesn't mean that I will implement it now.
Re: Go-lang like interface
My use cases would be virtually identical to the vtable usage of the standard library for things like streams. I just find that syntax extremely annoying and would love to have it abstracted away without having additional runtime costs. In my perfect world this would be an addition to concepts, so that they can either make the function implictely generic as they do now or do dynamic dispatch via implicitely generated vtable. With that said I also would prefer the pointers to be dereferenced before the proc is called. That way keeping it alive out of scope would be save and you still could use a var param to get it mutably. That way interfaces would also mirror the static duck typing awesomeness and clean syntax you generally have in nim while also having the advantages of dynamic dispatch where necessary. Finally, I do agree that type reflectoon on interfaces doesn't really seem necessary. The tight coupling seems to remove the whole purpose the interface had in the first place. An if you aren't interested in that there are, like, three other ways to do the same thing with less overhead and ugly hacks. Any use case that couldn't be solved with variant types, methods or generics more cleanly?
Re: Go-lang like interface
What's a pity _interface_ is a keyword so it can't be used for declaring interfaces. Interfaces can become particularly handy if used as a result type, it seems to me. Either way, it would be great to provide interface inheritance: createInterface HealthGenerator: proc genHealth(g: HealthGenerator): Health createInterface EnergyGenerator: proc genEnergy(g: EnergyGenerator): Energy createInterface BeautyGenerator of HealthGenerator, EnergyGenerator: proc genBeauty(g: BeautyGenerator): Beauty type Pear = ... proc genHealth(g: Pear): Health = ... proc genEnergy(g: Pear): Energy = ... proc genBeauty(g: Pear): Beauty = ... let pear = Pear(...) let beautifier: BeautyGenerator = pear # vtable's pointer points at p echo beautifier.genEnergy() echo beautifier.genHealth() echo beautifier.genBeauty() let energiser: EnergyGenerator = beautifier # new vtable's pointer still points at p echo energiser.genEnergy() #echo energiser.genHealth() # but has other procedure pointers #let other: BeautyGenerator = energiser # so the information is lost Making the converter interfaces-aware so that vtables aren't pointed but partially copied sounds easy as all the converter has to do is: * recognize the argument as an interface (interfaces inheriting from common type, easy) * check if all of the input interface's subroutines are present in the output interface A simple compile-time procedure returning bool value is all the converter needs. A runtime time label for interfaces sounds like an interesting idea but let's see what happens when we provide them: let pear = Pear(...) beautifier: BeautyGenerator = pear energiser: EnergyGenerator = beautifier other: BeautyGenerator = energiser.getType() if beautifier.realType of Pear: pearLover.eat(cast[ptr Pear](beautifier.obj)[]) getType() can't return the real type but a mere label. Still, if it can be used to retrieve the full type through a pointer cast, why not convert it to another (possibly wider) interface? proc burn(g: EnergyGenerator): Energy = result = g.genEnergy() if g.getType of SmokeGenerator: toSmokeGenerator(g).genSmoke() Well, it looks good, right? Well, it does if we forgot about memory usage. Notice that if any cast between the label and an interface label's type fulfils is valid at runtime, then it means all the subroutine pointers for that type must reside in memory. Not so funny if using a "popular" type. Which is why it sounds more reasonable to either not provide any type label at all or provide it only for explicit type casts, NOT conversions to other interfaces, which isn't obvious and may be confusing for some users if type-switch or similar transparent real-type-getters will be available.
Re: Go-lang like interface
@andrea I will test it a bit more and make sure that id doesn't have obvious bugs. I am also thinking of using concepts to make sure only data can be casted to an interface type that actually is compatible, and get nice error messages in case it doesn't work. Also the type switch or emty interface is not implemented yet. @Sixte I think I once read that blog. That blog supported me in my decision to not get stuck in the Go programming language, and keep searching for the best programming language. I put a lot of hope into the Rust programming language afterwards, and was hugely disappointed when I explored the macro capabilities. Then I found Nim was very enthusiastic. And even though, I think Go is a very limiting programming language, I really like it for it's simplicity and the very powerful intarface type. Then I thought if I could have the interface type of Go in Nim, it would be awesome. And then I did it. Even though I found lot's of bugs in Nim, I really like this language.
Re: Go-lang like interface
Some sceptical thoughts about the go language: "Why Go Is Not Good" [http://yager.io/programming/go.html](http://forum.nim-lang.org///yager.io/programming/go.html) audiatur et altera pars ^^
Re: Go-lang like interface
@Tarmean I now also did what you did, and I am posting my code here. I don't update the original post, because it would require me to either update the entire code there and rewrite things, or break compatibility with the example and the macro code. So I just post it here: import macros macro implementInterface(interfaceName: typed) : untyped = let interfaceNameStr = $interfaceName.symbol vtableSymbol = interfaceName.symbol.getImpl[2][2][1][1][0] vtableRecordList = vtableSymbol.symbol.getImpl[2][2] let objectConstructor = nnkObjConstr.newTree(vtableSymbol) for identDefs in vtableRecordList: let methodName = identDefs[0] params = identDefs[1][0] lambdaBody = quote do: cast[ptr T](this).`methodName`() call = lambdaBody[0] for i in 2 ..< len(params): let param = params[i] param.expectKind(nnkIdentDefs) for j in 0 .. len(param) - 3: call.add param[j] # leave out () when not needed if call.len == 1: lambdaBody[0] = call[0] methodName.expectKind nnkIdent objectConstructor.add nnkExprColonExpr.newTree( methodName, nnkLambda.newTree( newEmptyNode(),newEmptyNode(),newEmptyNode(), params.copy, newEmptyNode(),newEmptyNode(), lambdaBody ) ) let getVtableReturnStatement = nnkReturnStmt.newTree(newCall("addr", newIdentNode("theVtable"))) globalVtableIdent = newIdentNode("theVtable") getVtableProcIdent = newIdentNode("get" & interfaceNameStr & "Vtable") getVtableProcDeclaration = quote do: proc `getVtableProcIdent`[T](): ptr BananasVtable = var `globalVtableIdent` {.global.} = `objectConstructor` `getVtableReturnStatement` result = newStmtList() result.add getVtableProcDeclaration let castIdent = newIdentNode("to" & $interfaceName.symbol) result.add quote do: converter `castIdent`[T](this: ptr T) : `interfaceName` = `interfaceName`( objet : this, vtable : `getVtableProcIdent`[T]() ) result.add quote do: converter `castIdent`[T](this: var T) : `interfaceName` = `interfaceName`( objet : this.addr, vtable : `getVtableProcIdent`[T]() ) result.add quote do: converter `castIdent`(this: `interfaceName`): `interfaceName` = this echo result.repr macro createInterface*(name : untyped, methods : untyped) : untyped = name.expectKind nnkIdent let nameStr = $name.ident vtableRecordList = nnkRecList.newTree vtableIdent = newIdentNode(nameStr & "Vtable") vtableTypeDef = nnkTypeSection.newTree( nnkTypeDef.newTree( vtableIdent, newEmptyNode(), nnkObjectTy.newTree( newEmptyNode(), newEmptyNode(), vtableRecordList ) ) ) var newMethods = newSeq[NimNode]() for meth in methods: meth.expectKind(nnkProcDef) let methodIdent = meth[0] params = meth[3] thisParam = params[1] thisIdent = thisParam[0] thisType = thisParam[1] if thisType != name: error thisType.repr & " != " & name.repr let vtableEntryParams = params.copy vtableEntryParams[1][1] = newIdentNode("pointer") vtableRecordList.add( nnkIdentDefs.newTree( methodIdent, nnkProcTy.newTree( vtableEntryParams, newEmptyNode(), ), newEmptyNode() ) ) let call = nnkCall.newTree( nnkDotExpr.newTree( nnkDotExpr.newTree(thisIdent, newIdentNode("vtable")), methodIdent ), nnkDotExpr.newTree( thisIdent, newIdentNode("objet") ), ) for i in 2 ..< len(params): let param = params[i] param.expectKind(nnkIdentDefs) for j in 0 .. len(param) - 3: call.add param[j] meth[6] = nnkStmtList.newTree(call) newMethods.add(meth) result = newStmtList() result.add(vtableTypeDef) result.add quote do: type `name` = object objet : pointer vtable: ptr `vtableIdent` for meth in newMethods: result.add meth result.add newCall(bindSym"implementInterface", name) # optional if you want to see what you generated # echo result.repr And here is an example how to use it. Doesn't make a lot of sense, but yea it's just to show that it
Re: Go-lang like interface
That `{.global.}` usage is in fact pretty cool. I did not know of this behavior, but it makes sense, because static variables in c++ behave the same way. I guess I should use it, too.
Re: Go-lang like interface
Oh, forgot to re-add the unsafeaddr when returning, I had it removed to test the speed difference. The {.global.} variable is instantiated once for each type the generic proc is instantiated with, I think that is a way to get around having to call implementInterface. usage with macro then looks like this: defInterface Foo: proc bar(this: Foo): int type A = object B = object x: int proc bar(this: ptr A): int = 3 proc bar(this: ptr B): int = this.x var a = A() b = B(x: 5) a_i = a.toFoo() b_i = b.toFoo() collection = @[a_i, b_i] for entry in collection: echo entry.bar() On my first try I screwed up the vtable for procs with additional arguments but I think I fixed that. Macro ended up being very similar to yours, though.
Re: Go-lang like interface
I am not sure if it is intentional, but it looks like a bug: Why is `table` here global? let table {.global.} = MethodTable( foo: proc (this:pointer):int = cast[ptr T](this).foo ) EDIT: Btw that is the same way I started. I wrote a version that works without macros, and then I wrote a marco that would generate all the parts that could be automated.
Re: Go-lang like interface
Very cool idea! Tried to allow the interface to be implemented implicitly: type Interface = object obj: pointer vtable: MethodTable MethodTable = object foo: proc(this: pointer): int proc toInterface[T](t: var T): Interface = let this = addr t let table {.global.} = MethodTable( foo: proc (this:pointer):int = cast[ptr T](this).foo ) result = Interface(obj: this, vtable: table) proc foo(this: Interface): int = this.vtable.foo(this.obj) type A = object B = object proc foo(a: ptr A): int = 3 proc foo(a: ptr B): int = 5 var a = A() b = B() a_i = toInterface(a) b_i = toInterface(b) c = @[a_i, b_i] for e in c: echo e.foo() Works with two caveats: If toInterface is a converter and you try to use it implicitly nim generates illegal c code. And if toInterface is defined after exactly one implementation of foo() it breaks with > type mismatch: got (ptr A) but expected one of: proc foo(this: Interface): int If toInterface is a converter nim just straight up hangs up. If toInterface comes first or at least two foo()'s are defined before it everything works fine.
Re: Go-lang like interface
@OderWat that's the hard part, finding a good real world example. Real world example are most of the time either too complicated for an example or not suitable, because they have a simpler or better solution, which does not use this interface implementation. And then there is also the risk that the example is from a domain the reader will probably not understand. A really good example is an example where the interface type is superior to both the inheritance based approach, **and** the generics based approach. **Better than Generics:** * the function `foobar` should be somewhat complex, so that not using generics actually is an advantage. This could be done by having a complex macro call in the body that could eat some time of the compiler. You should know that a macro is evaluated after the generic instanciation. **Better than inheritance** * At least one interface implementation is part of some older library, where the auther that writes the interface has no acces to, and therefore can't add inheritance. * Or, the objects need to be very compact, so that adding a vtable to each object is a bad idea.
Re: Go-lang like interface
I think it would be easier to understand the code and the idear behind it if it would not use "MyInterface" and "MyImplementationX". I don't know how that is for other people by I would prefer them named after a (constructed) real world example instead.
Re: Go-lang like interface
This is a nice post, thanks for sharing. > This is not a question, more like a blog post. I don't have a blog so I do it > here. Feel free to comment or ask questions. I'm thinking it would be nice to start doing what D is doing: guest blog articles. I recently modified the website so that articles are standalone, turning it into a viable blog. Would you be interested in having this posted on [http://nim-lang.org](http://forum.nim-lang.org///nim-lang.org)?
Re: Go-lang like interface
Just if anybody wants / needs to know how to modify @Krux02 original code to automatically use a converter and therefor hiding more of the implementation details. Simply replace the lines from `let castIdent = ...` to the end of the file with: # instead of let castIdent = ... let converterIdent = newIdentNode($interfaceName.symbol & "Converter") result.add quote do: converter `converterIdent`(this: var `implementationCandidateName`) : `interfaceName` = `interfaceName`( objet : this.addr, vtable : `vtableValueSymbol`.unsafeAddr ) The example can simply call `foobar(a)` and `foobar(b)` after this modification.
Re: Go-lang like interface
@andrea Of course you are allowed to use this code, and I actually thought about putting it on github so it is more accessable to people. I am not so sure about the nimble package at this point in time. I will think about it.
Re: Go-lang like interface
@Krux02 It would be really nice to have these macros published on Nimble!
Re: Go-lang like interface
@bpr > That sounds like an anti-feature to me, kind of like the anti-feature of > Python (discussed on another thread here) that allows one to add object > attributes at any time. In Scala, Rust and more modern language, you can change external variable in funcational programming. And, this is why there are var parameters when you define Nim proc. No side effects will get lowwer performance.
Re: Go-lang like interface
@Krux02 > Yes, and you are ignorant to learn about them. HAHA. I don't learn about Golang because Golang is a lousy language. There are so many good languages better than Golang: C, Nim, Rust, Erlang, Scala, Java, Scheme. > Yes, live with it. "Pure function" are not realistic. Did you know Lisp is a functional programming language?
Re: Go-lang like interface
GoLang compilation recently took a big hit (2x to 10x slower for various apps) when the compiler was re-written from C to bootstrapped Go. Rob Pike was concerned, which I think is a good sign. With Go-1.7, it is almost as fast as 1.5 again. D2 on the other hand, though still fast, is quite a bit slower than D1. Here is a bit on how templates and other things were sped up in the D compiler: * [http://www.drdobbs.com/cpp/increasing-compiler-speed-by-over-75/240158941](http://forum.nim-lang.org///www.drdobbs.com/cpp/increasing-compiler-speed-by-over-75/240158941) One huge advantage of Nim and D over C++ is that a template specialization is instantiated only once (aside from inlining). I agree that templates can be a helpful feature of C++, and that they can also be abused to cause terrible compilation times. I have seen 1/2 hour compilation for a fairly small amount of code using Boost.Python and Boost.Serialization, and I hope never again to work at a company with that little regard for build times. In particular, I hope to avoid Scala, and for now also Rust. I will also say that I see some merit in Go's avoidance of generics. They're great for the coder, but they can be annoying to the reader. Different organizations may have different goals. > I'm not a Go programmer, but one obvious advantage I see from reading the > docs is that, unlike in Java, one doesn't need to define the types... > > That advantage is not unique to Go. The object system of the OCaml language > provides the same ability. Yes, @bpr, they are similar. The important thing is that you don't need to depend on the same interface file, as you would in Java (and C++, unless you trick the compiler). For a large project, it's important to be able to compile and test your own code without even downloading your dependencies. With a short build-time, you can simply rebuild the entire project, so this advantage becomes less important. But "coding to the interface" (with dependency inversion) is still a very good (and "SOLID") practice that is easier in some languages than in others. So I do appreciate your ideas, @Krux02, and I will look more closely at your macro when I have time.
Re: Go-lang like interface
@_tulayang > I had to say I didn't see any advantage of Go interface. I'm not a Go programmer, but one obvious advantage I see from reading the docs is that, unlike in Java, one doesn't need to define the types (rect and circle in the gobyexample example) as implementing a geometry interface, as one would have to do in Java. That advantage is not unique to Go. The object system of the OCaml language provides the same ability. > Side effects exsits in Scheme. You can call set! to change any external > variable anytime. That sounds like an anti-feature to me, kind of like the anti-feature of Python (discussed on another thread here) that allows one to add object attributes at any time. While I reject the dogma of pure functional programming, I think side effects should be localizable. Programming in a _mostly_ side-effect free style is a good thing. That said, I'm happy that Nim has generics, and even if it had some interface-like feature, I'd still want generics, just like many Go programmers do.
Re: Go-lang like interface
@jester I am sorry that you have this bad view on this thread. And I am very unhappy about the fact that this thread starts this way. Normally I really like to explain things, and help when someone does not understand something. I am also open to improvements in all directions. Even when the improvement is not a good idea I like to talk about what is not good about it. But someones posts _did not intend_ to improve on anything. @bpr Thank you, and yes that is true.
Re: Go-lang like interface
@OderWat > "This is so bad that several bigger c++ projects completely abandoned > templates. " ... is still not backed by even one example. You gave pointers > to Templates are very useful but are advanced and should not be overused > (google) and I personally don't like templates, but it is fine if you can > handle them (C. Muratori). Of course templates make stuff more complex and > can harm if you use them wrong or overuse them in general. Thats merely true > for everything though as Paracelsus pointed out a long time ago. Then you > imply that the reason why c++ templates are "bad" they also "may" make Nims > generics bad too. Something which you didn't experienced yourself (yet) and > nobody else did afaik. You are completely right here, and I should change my words in my original post. But you should also accept my experience that I had with templates. I worked in a project that grew since 2001 I think, and it is based on a lot of c++ template programming everywhere. It is a university project where a lot of Students work for about a year, and then leave the project again. This inherent overuse of templates encouraged the students to adapt the style of template programming, and they were used even more. Basically every function and datastructure that used a double was templated on the floating point type, because maybe one might want to compile it one day with `float`. So basically everything was templated. Compilation time exploded, and compilation was only possible on the cluster. My computer at home could not build the project I was working on at university, because it did not have enough RAM, and the cause was the overusage of templates. Since this day my perspective towards templates has changed, and I am very careful on the decision wheather I should use templates or if it is possible without. And I have not seen anything in the nim programming language that promises me that the same thing would happen the same way in the Nim world. There are simply no projects in Nim that have grown over 15 Years. > At the same time you promote a feature which could be seen much as a "patch" > for the missing generics in Go. In fact I remember that I read complaints > about Go not having a real generics implementation and have to copy code > eventually even with interfaces and delegates at hand. I do miss generics in Go. It somewhat works to live without them, but it is not nice. Just look at the [sorting example](https://gobyexample.com/sorting-by-functions) and you know what I mean. But I do not think that the interface type in Go is an afterthought to patch anything. The whole language is designed around the interface type, and I truely thing the go interface is a better solution to polymorphism than the vtable at the beginning of a class in languages like c++ C# and Java. > Then you prove (in my eyes) how ugly and cumbersome it is in the "black box > cast ptr macros" implementation you gave, while later you discard a real > elegant "see everything" functional approach to the problem as "cheating". I am sorry I don't understand than sentence. I don't think functional programming is cheating or bad. I really like and encourage functional programming. But it misses the point in what I tried to show. > You write: "I just don't like implicit conversions, I think they are scary, > because they hide procedure calls from the code reader, and could therefore > decrease code maintainability." but isn't this exactly what Go is doing in > its implementation? Yes it is. I will change it to use implicit converters. > Interfaces may be the best and elegant solution for Go programmers. But I > think that I would like to trade them for real generics and templates (which > I actually did). That is completely OK. But maybe you want to be open for an alternative for certain use cases. > EDIT: Using your macros together with a converter to hide the ugly details is > cool and may proof being useful. Thanks a lot.
Re: Go-lang like interface
Excitement and conviction don't have to be derisive. This feels like it's tending toward incivility.
Re: Go-lang like interface
> I had to say I didn't see any advantage of Go interface. Yes, and you are ignorant to learn about them. > "may not have side effects" ? Really? Yes, live with it. > I'm a fans of Scheme language which is a Lisp dialect. I hate Haskell. I hate > pure function. I think they are not realistic. It doesn't matter.
Re: Go-lang like interface
@Krux02 > The interface construct in Go works very different from the interface > construct in Java I had to say I didn't see any advantage of Go interface. > Can you tell me why your foobar in your functional solution has a function as > argument, instead of just passing it an int directly? This is just a demo. proc sort(x: var openarray[int], cmp: (a: int, b: int) -> bool) describes more. > Remember in functional programming functions may not have side effects. "may not have side effects" ? Really? I'm a fans of Scheme language which is a Lisp dialect. I hate Haskell. I hate pure function. I think they are not realistic. Side effects exsits in Scheme. You can call set! to change any external variable anytime.
Re: Go-lang like interface
@Krux02 "This is so bad that several bigger c++ projects completely abandoned templates. " ... is still not backed by even one example. You gave pointers to _Templates are very useful but are advanced and should not be overused_ (google) and _I personally don't like templates, but it is fine if you can handle them_ (C. Muratori). Of course templates make stuff more complex and can harm if you use them wrong or overuse them in general. Thats merely true for everything though as Paracelsus pointed out a long time ago. Then you imply that the reason why c++ templates are "bad" they also "may" make Nims generics bad too. Something which you didn't experienced yourself (yet) and nobody else did afaik. At the same time you promote a feature which could be seen much as a "patch" for the missing generics in Go. In fact I remember that I read complaints about Go not having a real generics implementation and have to copy code eventually even with interfaces and delegates at hand. Then you prove (in my eyes) how ugly and cumbersome it is in the "black box cast ptr macros" implementation you gave, while later you discard a real elegant "see everything" functional approach to the problem as "cheating". You write: "I just don't like implicit conversions, I think they are scary, because they hide procedure calls from the code reader, and could therefore decrease code maintainability." but isn't this exactly what Go is doing in its implementation? Interfaces may be the best and elegant solution for Go programmers. But I think that I would like to trade them for real generics and templates (which I actually did).
Re: Go-lang like interface
The interface construct in Go works very different from the interface construct in Java. And I did explain the differences. Please don't assume because you know how `interface` in java works, you know how `interface` in go works. I will add a note in my original post, so further people who read this do not make the same wrong assumtion as you did. Can you tell me why your `foobar` in your functional solution has a function as argument, instead of just passing it an `int` directly? Remember in functional programming functions may not have side effects.
Re: Go-lang like interface
@Krux02 I know interface of Java. Go is nothing magical.
Re: Go-lang like interface
@OderWat I was looking for examples online, because I remember that one of the c++ talks mentioned that they completely forbid the usage of templates. But I can't find that specific talk anymore. I saw too many, and did made a protocol about talks I watched. But what I did find is first of all, The google style guide which discourages to use [template metaprogramming](https://google.github.io/styleguide/cppguide.html#Template_metaprogramming). But to be fair, they don't completely ban templates, and I am not sure if they distinguish between normal templates as a replacement for generics, or more complicated things that rely on template specialization (which is something that Nim does not support in its generics for a good reason). Then I found is the live coding channel [Handmade Hero](https://handmadehero.org/) from Casey Muratori. His goal is to write an entire game with interesting game engine techniques completely on stream. He also says he won't use any third party libraries, he even refuses to use operating system abstractions like SDL. I don't know exactly where is says that he wouldn't use templates at all, but hiss 3D math library (vectors) with most people would implement with c++ templates is completely template free. Then there is also Jonathan Blow the writer of _Braid_ and _the Witness_. When you watch his streams you also realizes that he has a very strong opinion againt c++ templates. but again I don't know exactly where in is videos you find it, and unlike Handmade Hero I do not have access to his sourcecode. @_tulayang First of all, do you know the go programming language? [Here](https://gobyexample.com/interfaces) is an example of it's interface type. Do you understand it? To your _alternative solutions_, it is nice that you can prove to be able to program, but when you don't understand the point of the original version, and what it is supposed to show, or what its advantages are, then your solutions are not helpful at all, because they miss the point. * **functional solution**, first of all it's not more functional than my solution, just because it uses a lambda expression. But most importantly you degraded `foobar` to nothing more than an apply function and copy pasted it's logic into each call of foobar. * **Another solution**, I see three problems in this line alone: `type MyImplementationA = ref object of MyInterface`. 1. MyImplementationA now needs to be a referenced type, no stack allocation possible anymore. 2. Usage of MyImplementationA now forces garbage collection, and therefore also garbage collection overhead. 3. It uses direct inheritance from the interface type, which is a dependency that Go interfaces do not have. So please ask questions before you write another "solution".
Re: Go-lang like interface
Another solution: import future type MyInterface = ref object of RootRef foo: proc(this: MyInterface): int bar: proc(this: MyInterface): int proc foobar(this: MyInterface): int = return this.foo(this) + this.bar(this) type MyImplementationA = ref object of MyInterface MyImplementationB = ref object of MyInterface m_foo, m_bar: int proc newMyImplementationA(): MyImplementationA = result = new(MyImplementationA) result.foo = proc (this: MyInterface): int = 17 result.bar = proc (this: MyInterface): int = 4 proc newMyImplementationB(m_foo, m_bar: int): MyImplementationB = result = new(MyImplementationB) result.m_foo = m_foo result.m_bar = m_bar result.foo = proc (this: MyInterface): int = MyImplementationB(this).m_foo result.bar = proc (this: MyInterface): int = MyImplementationB(this).m_bar var a = newMyImplementationA() var b = newMyImplementationB(32, 8) echo foobar(a) echo foobar(b)
Re: Go-lang like interface
@Krux02 OK. If you're worried about code bloated, the best way is not to use interface, try functional programming (object-oriented programming is inflexible): import future type MyImplementationA = object MyImplementationB = object m_foo,m_bar: int proc foo(this: MyImplementationA): int = return 17 proc bar(this: MyImplementationA): int = return 4 proc foo(this: MyImplementationB): int = return this.m_foo proc bar(this: MyImplementationB): int = return this.m_bar proc foobar(f: () -> int): int = return f() var a = MyImplementationA() var b = MyImplementationB(m_foo: 32, m_bar: 8) echo foobar(() => a.foo() + a.bar()) echo foobar(() => b.foo() + b.bar())
Re: Go-lang like interface
@Krux02: "Ok, I will search for examples" ... I still wait for them.
Re: Go-lang like interface
@_tulayang It would be nice to know, where you lost my explanation, or where you started to skip reading it, because the point was to create a single type that can be used to implement `foobar`, and both `MyImplementationA` and `MyImplementationB` can be casted to this single type. Of course using generics for `foobar` works, too, but that has the disadvantage, that for each type `T` foobar is called, a new version of that get's compiled. That's not generally a bad thing, but the disadvantage is that in some cases generics, or templates (how generics are called in c++) can cause code bloat.
Re: Go-lang like interface
How about: type MyImplementationA = object MyImplementationB = object m_foo,m_bar: int proc foo(this: MyImplementationA): int = return 17 proc bar(this: MyImplementationA): int = return 4 proc foo(this: MyImplementationB): int = return this.m_foo proc bar(this: MyImplementationB): int = return this.m_bar proc foobar[T](mi: T): int = return mi.foo() + mi.bar() var a = MyImplementationA() var b = MyImplementationB(m_foo: 32, m_bar: 8) echo foobar(a) echo foobar(b)
Re: Go-lang like interface
+1 Awesome!
Re: Go-lang like interface
@jangko what do you mean with simulated inheritance? In Go you can have an [embedded type in a struct](https://golang.org/ref/spec#Struct_types). That means your struct has all methods, that the embedded type also has. This is effectively pretty much like multiple inheritance. So what simulated inheritance is not possible in Go?
Re: Go-lang like interface
surprisingly, this Go like interface is very similar with what I have implemented when creating high level wrapper for Chromium Embedded Framework in [nimCEF](https://github.com/jangko/nimCEF). in my experience, Nim macro not only capable simulate Go like interface, but also interface + simulated inheritance. Indeed Nim's macro can make Nim a very powerful language.
Re: Go-lang like interface
@bpr I never said that monomorphization is a harmful language feature. I just say that someone needs to be aware of it, and that in some contexts this monoporphization is in fact a bad thing. But in c++ it actually is harmful, because the way c++ deals with templates is, to create all required instances **per** compilation unit, and then at link time the linker throws all duplicates away. And that I consider as harmful, because the same function might get compiled 100 times and then gets thrown away 99 times. But the problem here is more on the way how c++ compiles its sourcecode, and not on how templates generally work. c++ has the same problem with datatypes that are declared in headers.
Re: Go-lang like interface
Rust, by design, also has C++-like monomorphizing templates, so I think it isn't fair to imply that templates (i.e., generics implemented by monomorphization) are a "considered harmful" language feature these days. As Araq points out, D, especially D2, is a template heavy language which mostly compiles pretty quickly.
Re: Go-lang like interface
> Which ones exactly? LLVM, wxWidgets, Urho3D, Ogre, Unreal Engine 4 and even > GCC afaik all use templates. We're not in the 80ies anymore where templates > where this special bug ridden feature with stupid syntax that nobody > understood. Ok, I will search for examples, and update the post accordingly. I definitively heared it in talks about c++. And listing big projects that use templates does not beat the argument. Additionally I've heard from Unreal Engine 4 developers, that changing the source code has very long builds, even long incremental builds maybe because of templates, but that not a prove and not my own experience. > Go's compile times are nothing special at all. Nim sometimes beats Go's > compile times, Delphi always beats it, D can beat it and yet D too has > extensive templating everywhere... Ok I did not do the benchmark, but correct would be that Go advertises with fast compilation speed. But you are right, in my experience it was not too fast. In my code is was always slower than advertised :/. But I can't exclude that I did something wrong that cause this increased compilation speed, because I never programmed in pure Go, I always had wrappers.
Re: Go-lang like interface
Nice work, but please refrain from facts/myths that don't have anything to do with your otherwise very nice article. > This is so bad that several bigger c++ projects completely abandoned > templates. Which ones exactly? LLVM, wxWidgets, Urho3D, Ogre, Unreal Engine 4 and even GCC afaik all use templates. We're not in the 80ies anymore where templates where this special bug ridden feature with stupid syntax that nobody understood. > If you remember one of Go's main features is it's compilation speed. Go's compile times are nothing special at all. Nim sometimes beats Go's compile times, Delphi always beats it, D can beat it and yet D too has extensive templating everywhere...