Re: Provide access to a class without access to the constructor

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Peter Duniho

    Re: Provide access to a class without access to the constructor

    On Fri, 11 Apr 2008 01:43:52 -0700, Weeble <clockworksaint @gmail.com>
    wrote:
    The difference is that A has ConsumeB, which takes an IB as a
    parameter.
    That's not a difference. The code example you compared to has the
    implication that A will use the IB instance passed back from the GetB
    method. After all, that's why the return type for GetB is IB, rather than
    B.
    It can't take a B as a parameter, because B is private to
    A. So it only has strong guarantees about the methods that are
    available, not what they do.
    That's why you define the interface in a way that provides the guarantee
    you need. This doesn't enforce the semantics, but it does provide
    implementors with very strond indications regarding what the
    implementations should do

    For example:
    Well, in the rather more complicated example that inspired this, B
    contains a transformation matrix which, at least when constructed by
    A, is known to be a rotation. It's quite awkward (though certainly
    possible) to verify if a given matrix is a pure rotation, but it's
    quite easy to compose one out of other known rotations.
    In that case, you need to write an interface that represents itself only
    in terms of rotation. It can return a matrix (cloned, so that you don't
    allow external mutation of internal state) as a convenience, but the API
    should be strictly in terms of rotating. Even better is for the interface
    to be immutable. You can only create an instance by providing a rotation,
    or by combining existing instances. The interface would include the
    latter operation, and of course the implementor provides the former.

    You could either make the assumption that the implementor has followed the
    semantics of the interface or, if you really think it's that important,
    it's not hard to inspect a transformation matrix and determine whether it
    only rotates. This is more flexible than insisting on your own
    implementation, if doing that bothers you.

    Personally, I think it's fine to make an assumption about whether the
    interface is implemented with the intended semantics. For one, you never
    know: perhaps some day someone will find a need to provide an
    implementation that does something other than just rotate. For another,
    if it's true that your own code will really break unless that condition is
    met, then that should be readily apparent as soon as someone tries to use
    an incorrect implementation. To some extent, I find it reasonable to rely
    on testing to ensure correctness. Not everything about the correctness of
    the code can be represented by the API that code exposes.

    That said, I have the impression that you're not all that enthusiastic
    about using interfaces to address this. And that's fine.
    [...]
    >You can't really guarantee that. But you can, as I mentioned in my
    >previous reply to your message, at least check the type of the
    >implementing instance to make sure it's B. Presumably that's really all
    >you care about anyway.
    >
    I certainly *could* do, but that feels very against-the-grain. It
    seems like it should be possible to solve this at compile-time. I was
    inspired by recent articles by Eric Lippert, such as:

    as well as his previous series on immutable data types. It made me
    think that I could and should be using the type system and access
    controls to provide stronger guarantees about the behaviour of my
    classes.
    Well, as has been noted, you can. I think that using "internal" is the
    best way, personally. I agree that nesting the classes can get out of
    hand, and for no real good reason.

    You might need to adjust your thinking, so that you're willing to treat
    assemblies as legitimate compilation divisions. But it seems like they
    offer the separation you're looking for here.

    Pete

  • Weeble

    #2
    Re: Provide access to a class without access to the constructor

    On Apr 11, 6:32 pm, "Peter Duniho" <NpOeStPe...@nn owslpianmk.com>
    wrote:
    On Fri, 11 Apr 2008 01:43:52 -0700, Weeble <clockworksa... @gmail.com>
    wrote:
    >
    The difference is that A has ConsumeB, which takes an IB as a
    parameter.
    >
    That's not a difference. The code example you compared to has the
    implication that A will use the IB instance passed back from the GetB
    method. After all, that's why the return type for GetB is IB, rather than
    B.
    I don't quite follow you here. GetB returns an IB, but we do know it's
    really a B. GetB is a public method, and B is private, so it could not
    have a return type of B. In contrast, the IB passed into ConsumeB
    really could be some non-B class.

    [Rotation stuff]
    In that case, you need to write an interface that represents itself only
    in terms of rotation. It can return a matrix (cloned, so that you don't
    allow external mutation of internal state) as a convenience, but the API
    should be strictly in terms of rotating. Even better is for the interface
    to be immutable.
    I do like immutable classes. :)

    That said, I have the impression that you're not all that enthusiastic
    about using interfaces to address this. And that's fine.
    In the end I didn't use interfaces for this one. Rotations have a
    public constructor that guarantees to make a proper rotation, and a
    private constructor that is used by the methods that compose or
    transpose rotations.
    You might need to adjust your thinking, so that you're willing to treat
    assemblies as legitimate compilation divisions. But it seems like they
    offer the separation you're looking for here.
    Actually, I was originally going to use assemblies for these kind of
    divisions, but apparently it causes some sort of problems to have too
    many assemblies, so I've been discouraged from doing this. (I can see
    that it's annoying to have to add lots of references to each project,
    though.) And when I have one huge assembly with lots of classes, some
    of which need access to others' internal methods, it gets hard to make
    it clear which classes should be using the internal methods and which
    shouldn't.

    Thanks for all the advice! It's been an interesting puzzle, but I
    think I've finally dodged the nasty parts and found a solution that's
    going to be at least moderately idiot-proof.

    Weeble.

    Comment

    Working...