I don't like too much Framework Design Guidelines... for many reason For example. such ideas about interface seem underlying a vague misunderstanding of object orientation itself.
When you use abstract class designed to be extendend you are defining the core behaviour of your class (even from a tecnical point of view). Than you add template methods and/or virtual ones to allow the extenders to change SOME behaviour. Moreover if the class is not stateless, there should be few of these template methods, or the different behaviour added could make the state inconsistent. And what if he want to change all the behaviours? Wrongly designed interfaces surely suffer of the problem you say.. but rightly designed ones no. Moreover, you should better consider the target. The interfaces that FxDG talks about are designed to be exposed to programmers with few (or none) knowledge about the domain the interfaces belong. For such programmers abstract classes are better. But for programmers who really understand the underling domain abstract class with no interface could be a problem. Better: the problem would be to affect code that rely on the abstract classes they do not want to use. "Fully" abstract classes (classes with no method's implementation) do not suffer of this problem, but what's the difference from interfaces (a part for be constrained to single inheritance). The programmers who try to go inside the code of DbLinq need to have understanding of what they are doing. But than, they should have the power of changing the behaviour "easily". The interfaces we are talking about are "internal", and they could be very usefull for such skilled programmers. Non skilled programmers would not try to go so deeper to get problem from the interface presence. That said, I think too that there are a few removable interfaces in DbLinq, but they should be carefully analized (and often are signals of required refactoring). But I think also that easy mantainence is not a reason to remove an useful interface (when it's rightly designed, i mean) Giacomo On Fri, May 8, 2009 at 1:04 PM, Jonathan Pryor <[email protected]> wrote: > Again, loose coupling doesn't require interfaces. It requires overridable > members (which can be done by both interfaces and classes with abstract and > virtual members). > > Again, see what Microsoft did with System.Data -- in .NET 1.0 we had e.g. > IDbConnection, while .NET 2.0 added the abstract DbConnection type, which > has the same members as IDbConnection, but adds additional > virtualfunctionality (e.g. > DbConnection.ConnectionTimeout, DbConnection.EnlistTransaction(), etc.). > Classes make it easier to add additional functionality over time w/o causing > breaking changes for implementing classes. > > If you have a copy of *Framework Design Guidelines*, I strongly suggest > you read ยง9.7 *Optional Feature Pattern*, which gives a short example of > what System.IO.Stream would look like if it were made of interfaces > instead of an abstract class, and the difficulties to consuming developers > in accessing the added functionality. The short version is that if you want > to add new functionality, you can't change the interface, so you need to add > new ones, and perform a runtime check for the added functionality, resulting > in code like: > > void OverwriteAt(IOutputStream stream, int position, byte[] bytes) { > ISeekableStream seekable = stream as ISeekableStream; > if (seekable != null) throw new NotSupportedException(); > stream.Seek(position); > stream.Write(bytes); > } > > as opposed to the current approach: > > void OverwriteAt(Stream stream, int position, byte[] bytes) { > if (!stream.CanSeek || !stream.CanWrite) throw new > NotSupportedException(); > stream.Seek(position); > stream.Write(bytes); > } > > The former is difficult for many developers to make use of, while the > latter allows code completion to be useful (as and casts don't work well > with code completion -- you need to *know* which interfaces to test for in > order to perform the conversion). > > This is why, among other reasons, the FxDG suggests classes over > interfaces: better versioning. The only places interfaces *must* be used > is when you need to support structs and/or classes that need to inherit from > other types. > > - Jon > > > On Fri, 2009-05-08 at 13:46 +0200, Pascal Craponne wrote: > > That's probably my fault: I added a lot of interfaces to DbLinq, with the > idea to add modularity. Anyway, even if you remove interfaces, it's still > easy to reintroduce them later (with tools like ReSharper, for example). > > Since you're much more active on the product than I am, if you feel the > interfaces cause too many problems, then remove some of them. > > But I'm not fan of removing interfaces between the core and the vendors, > since that's exactly the interface purpose: keeping loose coupling between > the modules. > > On Fri, May 8, 2009 at 05:05, Jonathan Pryor <[email protected]> wrote: > > So interfaces should be used each time that we could imagine a different > implementation with the same shape: adding a method could add a behaviour > not change an existing one. > > Then what's the difference between an interface and an abstract class > (or a class with all virtual members)? Both allow you to implement the > methods to support new functionality. > > The difference is that interfaces don't "burn your base class", which > doesn't appear to be an issue here. On the plus side, you can use > interfaces with structs -- but we're not using structs, so I'm not sure > that's relevant. I also don't currently see in which circumstances loses > the base class would actually be detrimental. Again, with classes you can > make the members virtual, thus allowing base classes to override them and > provide new functionality. > > You're right that adding a new method can only add behavior, not change > existing one -- so behavioral changes would require changing all existing > implementations *anyway*, for both interfaces and classes -- but classes > make adding additional considerably easier. > > So why do we *need* interfaces for many of our current uses? What makes > interfaces superior to abstract classes, for our current uses? I'm not > seeing any use of multiple-inheritance, nor value types, so I don't > currently see any circumstances that would *require* interfaces. > Meanwhile, using classes would permit easier sharing of implementation code > (which is why everybody inherits from SqlProvider instead of > re-implementing ISqlProvider), makes it easier to add additional > non-behavioral-changing functionality, and thus simplifies maintenance. > > - Jon > > > > > On Thu, 2009-05-07 at 22:43 +0100, Giacomo Tesio wrote: > > just some: > 3: in the medium term, I hope to find time to move dblinq to a better > service location infrastructure. > (actually i'm thinking about the Common Service Locator) > > I agree that some interfaces could be removed, but some should not (as > IQueryCache for example). We should only remove those interfaces that are > too much coupled with their user and/or their implementer that there's no > sane reason to reimplement in an alternative way. > (an example could be IDataMapper as far as I remember). > > But such interfaces often are index of a deep refactoring needed (as the > IDataMapper for example). > > I don't agree that interfaces complicate mantainence. When correcly > designed they have a single abstract responsibility, making mantainence far > easier, and allow to parallelize the programmers' work. > > So interfaces should be used each time that we could imagine a different > implementation with the same shape: adding a method could add a behaviour > not change an existing one. > > BTW when no other behaviour are possible (becouse of the coupling) we could > remove interface (but adding a TODO: evaluate refactoring needs here) > > > Giacomo > > On Thu, May 7, 2009 at 9:42 PM, Jonathan Pryor <[email protected]> wrote: > > I'd like to start a discussion about "cleaning up" the DbLinq source tree. > I have two annoyances I'd like to clean up. > > First #if removal. I understand (and support) the need for #ifs > (especially since they're needed for Mono). I don't think we need to use > #if as often as we do, though. Consider this, from > src/DbLinq/Data/Linq/Sugar/Implementation/QueryCache.cs: > > #if MONO_STRICT > namespace System.Data.Linq.Sugar.Implementation > #else > namespace DbLinq.Data.Linq.Sugar.Implementation > #endif > { > internal class QueryCache : IQueryCache > > The class is internal, and thus will never be exported from the > assembly. Other assemblies are public, but only for the !MONO_STRICTbuild. > > Consequently, I would like to remove most of these, and just stick to the > DbLinq root namespace. > > Secondly, and more likely controversially, I'd like to remove most of the > interfaces (e.g. ISqlProvider, etc.), for several reasons: > > 1. FxDG suggests using classes over interfaces most of the time, because of > easier versioning. You can easily add methods to classes without "breaking" > existing derived types, but it's not possible to add new methods to > interfaces. (See also the earlier email for fixing .Count() SQL > generation.) For comparison, consider how .NET 1.0 had the IDb*interfaces, > while .NET 2.0 moved to the > Db* classes. Easier versioning is useful. > > 2. Most derived types are already using the helper classes instead of the > interfaces. > > 3. The interfaces *complicate* maintenance. If use VS.NET and you're in a > method, e.g. QueryBuilder.BuildSqlQuery(), and you right-click > SqlBuilder.BuildSelect(), right-click, and click *G*o To Definition, you > wind up at the interface definition. That's not very useful. Especially > since we use ObjectFactory.Get<T>(), so there can really only be one > implementation for the ISqlBuilder interface *anyway*. The "workaround" > is to use Find All References, which is slower and cumbersome compared to Go > To Definition. This is clunky. > > 3.a. Another place where maintenance is complicated is in the necessary > duplication of methods between the interface and the implemented types. > When this is needed, it's a necessary complication, but I don't see the need > for it. The result is that if you need to add behavior that requires > changing an interface, you change the interface and all implementations > (even when -- *especially when* -- there's a sane default behavior for the > added method). > > 4. The use of interfaces leads to having nested Implementation directories > everywhere, which makes for "deeper" project solutions and longer namespace > names (and thus harder to navigate to files within the VS Solution > Explorer). I would like to remove them, thus "flattening" the project > directory structure. > > Thoughts? > > - Jon > > > > > > > > > > > > > > > > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "DbLinq" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/dblinq?hl=en -~----------~----~----~----~------~----~------~--~---
