On Wed, May 02, 2018 at 12:11:57AM -0400, Nick Sabalausky (Abscissa) via Digitalmars-d wrote: > On 04/30/2018 05:35 PM, H. S. Teoh wrote: > > > > Also, design by introspection. Dependence on explicit types is so > > last century. Design by introspection FTW! Decoupling your code > > from explicit types makes it more encapsulated, and gives you > > incentive to write more defensively, resulting in better, more > > change-resilient code. When an upstream library changes a return > > type, you can just recompile and go, rather than waste time patching > > the 150 different places where the explicit type was named. Let the > > machine do the work for you! > > > > There's a lot about that I like too, but I really wish D didn't use > structral typing to do it. I still think the only reason D's structral > typing hasn't blown up in our faces is because it's still mostly > limited to the basic ranges isn't not a prevalent part of most > internal and external APIs. Structural typing basically amounts to a > form of global namespace (which can also work out ok *if used > sparingly*, not that I'd want to try). At first, D thankfully killed > off the global namespace for the most part...but then it brings its > pitfalls right back in the form of structural typing. Grrr...
I've been using structural typing / design by introspection to good success in my latest project, actually. I was writing a submodule that handled interfacing with POVRay for 3D rendering (non-realtime, obviously), and wanted a clean API that didn't force tons of boilerplate on you. The main problem here is that POVRay has so many features, knobs, and dials that either you have to dumb things down so much that you're no longer using most of its features, which defeats the purpose of using it(!), or you have to essentially reinvent SDL in your API so that your users have access to everything they might need, which makes your API so complex and hairy it would require Java-style verbosity, complete with factory classes, wrapper types, a class hierarchy, and gratuitousUnreasonablyLongIdentifiers, just to initialize it to do something as simple as rendering a couple of polygons. Eventually, I settled on DoI by specifying some basic required properties for, say, polygons to be output as a mesh, y'know, vertex coordinates and lists of vertex indices for the polygons, with many optional parameters checked by static if. So if you wanted just to output a couple of polygons with flat textures, all you have to do is to pass in an array of vectors and an array of int[]'s, and off you go. If you wanted different textures for each polygon, make a struct that aliases int[] to this (or overloads opIndex) plus a .texture field to specify the texture. If you wanted surface normal interpolation, wrap your vectors in a struct that has a .normal field specifying the normals to interpolate. On the implementation side, it's just a bunch of static if's that optionally checks if a property is present, and provide implementation for it if it is. If it weren't for DoI, I would've ended up with a big, complicated API with tons of boolean switches or a class hierarchy to provide for all the variations that might be needed, and it would have required a ton of boilerplate just to output a couple of flat polygons. With DoI, I get to scale the amount of initialization code I need according to how many features I will actually use. > Structral typing isn't "If it walks like a duck and quacks like a > duck...". Structural typing is "If it walks and it talks, then it > must be a duck, because ducks walk and have their own form of talk, so > clearly anything that walks and talks must be a duck." How else would you do DoI, though? With Concepts? The advantage of using structural typing over concepts for DoI is that you would need an exponential number of concepts to catch up with a linear number of optional fields in a structural typing model. Sure, structural typing has its warts, but it's at least more scalable in this respect. T -- What do you call optometrist jokes? Vitreous humor.