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 virtual
functionality (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_STRICT build.
>         >         
>         >         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 Go
>         >         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
-~----------~----~----~----~------~----~------~--~---

Reply via email to