On Friday, May 13, 2016 18:41:16 Jamal via Digitalmars-d-learn wrote: > Warning D newb here. > > Is it possible to define a member function outside of the > class/struct like in C++; > > class x { body > void foo(int* i); > }; > > void x::foo(int* i){ > *i++; > } > > Or is it just D-like to define everything inside the class/struct > body?
The language is designed with the idea that you're going to define all of the functions inline and not have prototypes. So, if you're trying to do it differently, you're going to have a lot of problems. That being said, you have two options: 1. Write a D interface file. Its extension is .di, and it's intended to be similar to a C/C++ header file for the purpose of hiding implementation when distributing a library without the source code. However, you still need to write the .d file exactly like you would normally. The .di file is just for other folks that you don't want to give the source to. So, it generates a lot more work for you with arguably no benefit if you're just looking to separate interface and implementation. And any templated types and auto-return functions will still have to have their full source in the .di file, and any functions that you want to be inlined will need their source in the .di file. So, a lot of stuff is likely going to need to be in the .di file anyway (especially in range-based code, since that tends to be _very_ template-heavy). To save effort in generating a .di file, you can use the compiler to generate one for you (I think that the flags that start with -H are for that), but last I heard, it's pretty conservative in removing stuff, so a lot of the implementation is going to be left in there even if it doesn't need to be. So, you're likely going to have to edit it manually. I think that the general consensus in the D community has been that .di files really aren't worth it. If you _need_ them, because you want to keep your source hidden, then they're what you need, but they're a pain otherwise. 2. You can use UFCS (Universal Function Call Syntax). Ali's book talks about it here: http://ddili.org/ders/d.en/ufcs.html but basically what it comes down to is that you call call a free function as if it were a member function of its first argument. e.g. auto foo(MyClass m, int i) {..} auto result = myClass.foo(42); This allows you to essentially add member functions without them having to be member functions. You don't end up with prototypes or with them being listed as member functions in your struct or class, but the functions are then separate from the struct or class, and you don't need their implementation inside the struct or class. Where UFCS is truly useful though is it allows generic code to call functions without caring whether they're member functions or free functions. For instance, if you use std.algorith.find with UFCS inside of a templated function, and you call it with UFCS, and the type that you call it on has a member function called find which is more efficient for it than the generic find would be, then the member function will be called, whereas for all of those types that don't define find, the generic one will work just fine. So, your code doesn't have to care whether the function is actually a member function or not. But a lot of folks like to use UFCS just because it allows them to chain functions left-to-right rather than using the classical, functional style with parens, which chains right-to-left and ends up with a lot of parens. e.g. auto arr = [1, 7, 19, 42, 9]; auto result = arr.filter!(a => a < 20)().map!(a => to!string(a))().array(); assert(result == ["1", "7", "19", "9"]); or auto arr = [1, 7, 19, 42, 9]; auto result = arr.filter!(a => a < 20)() .map!(a => to!string(a))() .array(); assert(result == ["1", "7", "19", "9"]); instead of auto arr = [1, 7, 19, 42, 9]; auto result = array(map!(a => to!string(a))(filter!(a => a < 20)(arr))); assert(result == ["1", "7", "19", "9"]); In any case, D is set up so that you don't normally separate declarations and definitons like you would in C/C++, and its compilation model is _far_ more efficient than C/C++, so it's not really necessary to do it in quite the same way that it is in C/C++. It is occasionally annoying when you just want to see which member functions and member functions are declared on a type, but you get used to it, and you can always generate documentation to if you just want to see the declarations. We're in basically the same boat as Java with this sort of thing. - Jonathan M Davis