This page is no longer maintained — Please continue to the home page at www.scala-lang.org

"private class tunnel"

10 replies
H-star Development
Joined: 2010-04-14,
User offline. Last seen 2 years 26 weeks ago.

hi,

in lack of a better word, i named my idea a "private class tunnel"
in every single one of my project, i had 2 kinds of public methods: real
public methods that anyone is allowed to call and methods that have to
be public, but are only called from other classes that are "connected by
intention"

a simple example:
2 classes A and B. A holds a list of B. whenever a B is added to A, A
calls "notifyAdded" on B. B has to offer a public method named
notifyAdded, so anyone can call the method, but only A is supposed to.
anyone else would destroy internal states.
i cannot solve this problem. either the method is private, and B can't
call it, or it's public and anyone can.

what would solve this is a "private class tunnel", a method that is
declared as only callable from specified call sites. i think that's
worth thinking about. or does scala already offer something like this?

Kevin Wright 2
Joined: 2010-05-30,
User offline. Last seen 26 weeks 4 days ago.
Re: "private class tunnel"
In addition to ScalaDoc, you basically have two options depending on the nature of your project.
1. If it's a standalone project that only you (or a small team) are writing, then just don't call that method in the wrong way.
2. If it's a library-style project to be used by "clients", then make the method private, but in a wider package scope. i.e.:  private[some.parent.package] def notifyAdded = ...
There are also certain things that you can arrange to have enforced by the type system, but it doesn't sound like you have the right use-case for that.


On 18 July 2010 14:13, HamsterofDeath <h-star [at] gmx [dot] de> wrote:
hi,

in lack of a better word, i named my idea a "private class tunnel"
in every single one of my project, i had 2 kinds of public methods: real
public methods that anyone is allowed to call and methods that have to
be public, but are only called from other classes that are "connected by
intention"

a simple example:
2 classes A and B. A holds a list of B. whenever a B is added to A, A
calls "notifyAdded" on B. B has to offer a public method named
notifyAdded, so anyone can call the method, but only A is supposed to.
anyone else would destroy internal states.
i cannot solve this problem. either the method is private, and B can't
call it, or it's public and anyone can.

what would solve this is a "private class tunnel", a method that is
declared as only callable from specified call sites. i think that's
worth thinking about. or does scala already offer something like this?



--
Kevin Wright

mail/google talk: kev [dot] lee [dot] wright [at] gmail [dot] com
wave: kev [dot] lee [dot] wright [at] googlewave [dot] com
skype: kev.lee.wright
twitter: @thecoda

H-star Development
Joined: 2010-04-14,
User offline. Last seen 2 years 26 weeks ago.
Re: "private class tunnel"

it's 1), but following that argument i could make anything public and
just don't call anything that should be private. it would work, but it's
not ...nice. i'd like to put the "who's allowed to call this"-info
somewhere into the code at language level

2) this forces me to kind of misuse packages and put things together
that don't belong together.

a third possibliliy is a runtime check using aspectJ, but a compile time
check would simply be better

Kevin Wright schrieb:
> In addition to ScalaDoc, you basically have two options depending on
> the nature of your project.
>
> 1. If it's a standalone project that only you (or a small team) are
> writing, then just don't call that method in the wrong way.
>
> 2. If it's a library-style project to be used by "clients", then make
> the method private, but in a wider package scope. i.e.:
> private[some.parent.package] def notifyAdded = ...
>
> There are also certain things that you can arrange to have enforced by
> the type system, but it doesn't sound like you have the right use-case
> for that.
>
>
>
> On 18 July 2010 14:13, HamsterofDeath > wrote:
>
> hi,
>
> in lack of a better word, i named my idea a "private class tunnel"
> in every single one of my project, i had 2 kinds of public
> methods: real
> public methods that anyone is allowed to call and methods that have to
> be public, but are only called from other classes that are
> "connected by
> intention"
>
> a simple example:
> 2 classes A and B. A holds a list of B. whenever a B is added to A, A
> calls "notifyAdded" on B. B has to offer a public method named
> notifyAdded, so anyone can call the method, but only A is supposed to.
> anyone else would destroy internal states.
> i cannot solve this problem. either the method is private, and B can't
> call it, or it's public and anyone can.
>
> what would solve this is a "private class tunnel", a method that is
> declared as only callable from specified call sites. i think that's
> worth thinking about. or does scala already offer something like this?
>
>
>
>

Kevin Wright 2
Joined: 2010-05-30,
User offline. Last seen 26 weeks 4 days ago.
Re: "private class tunnel"
There's a strong argument in favour of making all methods public, especially now that we have inner methods available to us.
The theory is that if you have your class doing a bunch of private stuff, then the private behaviour should be moved into a new class and make public, with an instance of this new class being held in the original.  Private methods are often a code smell, and are very rarely seen in TDD code.
Applying this sort of logic to your own use-case, you might be able to move notifyAdded() into a trait that you mix-in to B when it's instantiated.  The method will continue to be public, but won't be present in B's formal interface.  It's hard if this is suitable for you without seeing the actual code though :P

On 18 July 2010 14:45, HamsterofDeath <h-star [at] gmx [dot] de> wrote:
it's 1), but following that argument i could make anything public and
just don't call anything that should be private. it would work, but it's
not ...nice. i'd like to put the "who's allowed to call this"-info
somewhere into the code at language level

2) this forces me to kind of misuse packages and put things together
that don't belong together.

a third possibliliy is a runtime check using aspectJ, but a compile time
check would simply be better

Kevin Wright schrieb:
> In addition to ScalaDoc, you basically have two options depending on
> the nature of your project.
>
> 1. If it's a standalone project that only you (or a small team) are
> writing, then just don't call that method in the wrong way.
>
> 2. If it's a library-style project to be used by "clients", then make
> the method private, but in a wider package scope. i.e.:
>   private[some.parent.package] def notifyAdded = ...
>
> There are also certain things that you can arrange to have enforced by
> the type system, but it doesn't sound like you have the right use-case
> for that.
>
>
>
> On 18 July 2010 14:13, HamsterofDeath <h-star [at] gmx [dot] de
> <mailto:h-star [at] gmx [dot] de>> wrote:
>
>     hi,
>
>     in lack of a better word, i named my idea a "private class tunnel"
>     in every single one of my project, i had 2 kinds of public
>     methods: real
>     public methods that anyone is allowed to call and methods that have to
>     be public, but are only called from other classes that are
>     "connected by
>     intention"
>
>     a simple example:
>     2 classes A and B. A holds a list of B. whenever a B is added to A, A
>     calls "notifyAdded" on B. B has to offer a public method named
>     notifyAdded, so anyone can call the method, but only A is supposed to.
>     anyone else would destroy internal states.
>     i cannot solve this problem. either the method is private, and B can't
>     call it, or it's public and anyone can.
>
>     what would solve this is a "private class tunnel", a method that is
>     declared as only callable from specified call sites. i think that's
>     worth thinking about. or does scala already offer something like this?
>
>
>
>
> --
> Kevin Wright
>
> mail/google talk: kev [dot] lee [dot] wright [at] gmail [dot] com
> <mailto:kev [dot] lee [dot] wright [at] gmail [dot] com>
> wave: kev [dot] lee [dot] wright [at] googlewave [dot] com <mailto:kev [dot] lee [dot] wright [at] googlewave [dot] com>
> skype: kev.lee.wright
> twitter: @thecoda
>




--
Kevin Wright

mail/google talk: kev [dot] lee [dot] wright [at] gmail [dot] com
wave: kev [dot] lee [dot] wright [at] googlewave [dot] com
skype: kev.lee.wright
twitter: @thecoda

H-star Development
Joined: 2010-04-14,
User offline. Last seen 2 years 26 weeks ago.
Re: "private class tunnel"

A.add(b:B with NotificationTrait) {..} ?

Kevin Wright schrieb:
> There's a strong argument in favour of making all methods public,
> especially now that we have inner methods available to us.
>
> The theory is that if you have your class doing a bunch of private
> stuff, then the private behaviour should be moved into a new class and
> make public, with an instance of this new class being held in the
> original. Private methods are often a code smell, and are very rarely
> seen in TDD code.
>
> Applying this sort of logic to your own use-case, you might be able to
> move notifyAdded() into a trait that you mix-in to B when it's
> instantiated. The method will continue to be public, but won't be
> present in B's formal interface. It's hard if this is suitable for
> you without seeing the actual code though :P
>
>
> On 18 July 2010 14:45, HamsterofDeath > wrote:
>
> it's 1), but following that argument i could make anything public and
> just don't call anything that should be private. it would work,
> but it's
> not ...nice. i'd like to put the "who's allowed to call this"-info
> somewhere into the code at language level
>
> 2) this forces me to kind of misuse packages and put things together
> that don't belong together.
>
> a third possibliliy is a runtime check using aspectJ, but a
> compile time
> check would simply be better
>
> Kevin Wright schrieb:
> > In addition to ScalaDoc, you basically have two options depending on
> > the nature of your project.
> >
> > 1. If it's a standalone project that only you (or a small team) are
> > writing, then just don't call that method in the wrong way.
> >
> > 2. If it's a library-style project to be used by "clients", then
> make
> > the method private, but in a wider package scope. i.e.:
> > private[some.parent.package] def notifyAdded = ...
> >
> > There are also certain things that you can arrange to have
> enforced by
> > the type system, but it doesn't sound like you have the right
> use-case
> > for that.
> >
> >
> >
> > On 18 July 2010 14:13, HamsterofDeath
> > >> wrote:
> >
> > hi,
> >
> > in lack of a better word, i named my idea a "private class
> tunnel"
> > in every single one of my project, i had 2 kinds of public
> > methods: real
> > public methods that anyone is allowed to call and methods
> that have to
> > be public, but are only called from other classes that are
> > "connected by
> > intention"
> >
> > a simple example:
> > 2 classes A and B. A holds a list of B. whenever a B is
> added to A, A
> > calls "notifyAdded" on B. B has to offer a public method named
> > notifyAdded, so anyone can call the method, but only A is
> supposed to.
> > anyone else would destroy internal states.
> > i cannot solve this problem. either the method is private,
> and B can't
> > call it, or it's public and anyone can.
> >
> > what would solve this is a "private class tunnel", a method
> that is
> > declared as only callable from specified call sites. i think
> that's
> > worth thinking about. or does scala already offer something
> like this?
> >
> >
> >
> >
> > --
> > Kevin Wright
> >
> > mail/google talk: kev [dot] lee [dot] wright [at] gmail [dot] com
>
> > >
> > wave: kev [dot] lee [dot] wright [at] googlewave [dot] com
>
> >
> > skype: kev.lee.wright
> > twitter: @thecoda
> >
>
>
>
>

Kevin Wright 2
Joined: 2010-05-30,
User offline. Last seen 26 weeks 4 days ago.
Re: "private class tunnel"
That's the idea, yes :)


On 18 July 2010 15:24, HamsterofDeath <h-star [at] gmx [dot] de> wrote:
A.add(b:B with NotificationTrait) {..} ?


Kevin Wright schrieb:
> There's a strong argument in favour of making all methods public,
> especially now that we have inner methods available to us.
>
> The theory is that if you have your class doing a bunch of private
> stuff, then the private behaviour should be moved into a new class and
> make public, with an instance of this new class being held in the
> original.  Private methods are often a code smell, and are very rarely
> seen in TDD code.
>
> Applying this sort of logic to your own use-case, you might be able to
> move notifyAdded() into a trait that you mix-in to B when it's
> instantiated.  The method will continue to be public, but won't be
> present in B's formal interface.  It's hard if this is suitable for
> you without seeing the actual code though :P
>
>
> On 18 July 2010 14:45, HamsterofDeath <h-star [at] gmx [dot] de
> <mailto:h-star [at] gmx [dot] de>> wrote:
>
>     it's 1), but following that argument i could make anything public and
>     just don't call anything that should be private. it would work,
>     but it's
>     not ...nice. i'd like to put the "who's allowed to call this"-info
>     somewhere into the code at language level
>
>     2) this forces me to kind of misuse packages and put things together
>     that don't belong together.
>
>     a third possibliliy is a runtime check using aspectJ, but a
>     compile time
>     check would simply be better
>
>     Kevin Wright schrieb:
>     > In addition to ScalaDoc, you basically have two options depending on
>     > the nature of your project.
>     >
>     > 1. If it's a standalone project that only you (or a small team) are
>     > writing, then just don't call that method in the wrong way.
>     >
>     > 2. If it's a library-style project to be used by "clients", then
>     make
>     > the method private, but in a wider package scope. i.e.:
>     >   private[some.parent.package] def notifyAdded = ...
>     >
>     > There are also certain things that you can arrange to have
>     enforced by
>     > the type system, but it doesn't sound like you have the right
>     use-case
>     > for that.
>     >
>     >
>     >
>     > On 18 July 2010 14:13, HamsterofDeath <h-star [at] gmx [dot] de
>     <mailto:h-star [at] gmx [dot] de>
>     > <mailto:h-star [at] gmx [dot] de <mailto:h-star [at] gmx [dot] de>>> wrote:
>     >
>     >     hi,
>     >
>     >     in lack of a better word, i named my idea a "private class
>     tunnel"
>     >     in every single one of my project, i had 2 kinds of public
>     >     methods: real
>     >     public methods that anyone is allowed to call and methods
>     that have to
>     >     be public, but are only called from other classes that are
>     >     "connected by
>     >     intention"
>     >
>     >     a simple example:
>     >     2 classes A and B. A holds a list of B. whenever a B is
>     added to A, A
>     >     calls "notifyAdded" on B. B has to offer a public method named
>     >     notifyAdded, so anyone can call the method, but only A is
>     supposed to.
>     >     anyone else would destroy internal states.
>     >     i cannot solve this problem. either the method is private,
>     and B can't
>     >     call it, or it's public and anyone can.
>     >
>     >     what would solve this is a "private class tunnel", a method
>     that is
>     >     declared as only callable from specified call sites. i think
>     that's
>     >     worth thinking about. or does scala already offer something
>     like this?
>     >
>     >
>     >
>     >
>     > --
>     > Kevin Wright
>     >
>     > mail/google talk: kev [dot] lee [dot] wright [at] gmail [dot] com
>     <mailto:kev [dot] lee [dot] wright [at] gmail [dot] com>
>     > <mailto:kev [dot] lee [dot] wright [at] gmail [dot] com <mailto:kev [dot] lee [dot] wright [at] gmail [dot] com>>
>     > wave: kev [dot] lee [dot] wright [at] googlewave [dot] com
>     <mailto:kev [dot] lee [dot] wright [at] googlewave [dot] com>
>     <mailto:kev [dot] lee [dot] wright [at] googlewave [dot] com
>     <mailto:kev [dot] lee [dot] wright [at] googlewave [dot] com>>
>     > skype: kev.lee.wright
>     > twitter: @thecoda
>     >
>
>
>
>
> --
> Kevin Wright
>
> mail/google talk: kev [dot] lee [dot] wright [at] gmail [dot] com
> <mailto:kev [dot] lee [dot] wright [at] gmail [dot] com>
> wave: kev [dot] lee [dot] wright [at] googlewave [dot] com <mailto:kev [dot] lee [dot] wright [at] googlewave [dot] com>
> skype: kev.lee.wright
> twitter: @thecoda
>




--
Kevin Wright

mail/google talk: kev [dot] lee [dot] wright [at] gmail [dot] com
wave: kev [dot] lee [dot] wright [at] googlewave [dot] com
skype: kev.lee.wright
twitter: @thecoda

Ben Hutchison 3
Joined: 2009-11-02,
User offline. Last seen 42 years 45 weeks ago.
Re: "private class tunnel"

On Sun, Jul 18, 2010 at 11:13 PM, HamsterofDeath wrote:
I had [...] methods that have to
> be public, but are only called from other classes that are "connected by
> intention" ... a method that is
> declared as only callable from specified call sites. i think that's
> worth thinking about.

+1. Your explanation is kind of informal, but the basic idea resonates with me.

I find that many methods are intended for by use a particular
"audience": persistence, security, clients, etc, not just the "general
public".

A way to express this might be useful, but I don't know of a general
way to achieve this in Scala (beyond what's nicely explained by Ted
Neward here: http://www.ibm.com/developerworks/java/library/j-scala07298.html#N10197).

I guess the "audiences" granted access to a method would have to be
specified by class or package name inside the access modifier, eg
private[org.hibernate] or similar?

-Ben

Brian Mosley
Joined: 2010-03-28,
User offline. Last seen 42 years 45 weeks ago.
Re: "private class tunnel"

So, you're essentially saying that you need friend classes a la C++ or
Eiffel. I don't think Scala
supports this. I can see how it would be a useful feature to have, but
unfortunately I think your
best defense here is going to be strong wording in the documentation.

On 7/18/2010 9:13 AM, HamsterofDeath wrote:
> hi,
>
> in lack of a better word, i named my idea a "private class tunnel"
> in every single one of my project, i had 2 kinds of public methods: real
> public methods that anyone is allowed to call and methods that have to
> be public, but are only called from other classes that are "connected by
> intention"
>
> a simple example:
> 2 classes A and B. A holds a list of B. whenever a B is added to A, A
> calls "notifyAdded" on B. B has to offer a public method named
> notifyAdded, so anyone can call the method, but only A is supposed to.
> anyone else would destroy internal states.
> i cannot solve this problem. either the method is private, and B can't
> call it, or it's public and anyone can.
>
> what would solve this is a "private class tunnel", a method that is
> declared as only callable from specified call sites. i think that's
> worth thinking about. or does scala already offer something like this?
>
>

extempore
Joined: 2008-12-17,
User offline. Last seen 35 weeks 3 days ago.
Re: "private class tunnel"

On Sun, Jul 18, 2010 at 09:48:21PM -0400, Brian Mosley wrote:
> So, you're essentially saying that you need friend classes a la C++ or
> Eiffel. I don't think Scala supports this.

This is scala we're talking about. It's always possible.

I'm not saying this is the best way. It's the first one I thought of,
and has the bonus of being a useful application of NotNull, something I
don't remember ever seeing before.

// A.scala
object A {
sealed trait AuthToken
private implicit object Auth extends AuthToken
}
class A {
import A._
var bs: List[B] = Nil
def add(b: B) = {
bs :+= b
b.notifyAdded()
}
}

// B.scala
class B {
def notifyAdded()(implicit auth: A.AuthToken with NotNull): Unit = println("Added " + this)
}

// Test.scala
object Test {
def main(args: Array[String]): Unit = {
val a = new A
a add new B
a add new B
}
}

// NoFriendOfMine.scala (doesn't compile, intentionally)
class NoFriendOfMine {
// Things to try.
//
// 1) import A._ (or as-is)
// error: could not find implicit value for parameter auth: A.AuthToken with NotNull
// b.notifyAdded()
// ^
// 2) implicit object Auth extends A.AuthToken
// error: illegal inheritance from sealed trait AuthToken
// implicit object Auth extends A.AuthToken
// ^
// 3) b.notifyAdded()(null)
// error: type mismatch;
// found : Null(null)
// required: A.AuthToken with NotNull
// b.notifyAdded()(null)
// ^

var bs: List[B] = Nil
def add(b: B) = {
bs :+= b
b.notifyAdded()
}
}

% scala Test
Added B@3295cfbe
Added B@1de58cb8

H-star Development
Joined: 2010-04-14,
User offline. Last seen 2 years 26 weeks ago.
Re: "private class tunnel"

implicit friends :D

Paul Phillips schrieb:
> On Sun, Jul 18, 2010 at 09:48:21PM -0400, Brian Mosley wrote:
>
>> So, you're essentially saying that you need friend classes a la C++ or
>> Eiffel. I don't think Scala supports this.
>>
>
> This is scala we're talking about. It's always possible.
>
> I'm not saying this is the best way. It's the first one I thought of,
> and has the bonus of being a useful application of NotNull, something I
> don't remember ever seeing before.
>
> // A.scala
> object A {
> sealed trait AuthToken
> private implicit object Auth extends AuthToken
> }
> class A {
> import A._
> var bs: List[B] = Nil
> def add(b: B) = {
> bs :+= b
> b.notifyAdded()
> }
> }
>
> // B.scala
> class B {
> def notifyAdded()(implicit auth: A.AuthToken with NotNull): Unit = println("Added " + this)
> }
>
> // Test.scala
> object Test {
> def main(args: Array[String]): Unit = {
> val a = new A
> a add new B
> a add new B
> }
> }
>
> // NoFriendOfMine.scala (doesn't compile, intentionally)
> class NoFriendOfMine {
> // Things to try.
> //
> // 1) import A._ (or as-is)
> // error: could not find implicit value for parameter auth: A.AuthToken with NotNull
> // b.notifyAdded()
> // ^
> // 2) implicit object Auth extends A.AuthToken
> // error: illegal inheritance from sealed trait AuthToken
> // implicit object Auth extends A.AuthToken
> // ^
> // 3) b.notifyAdded()(null)
> // error: type mismatch;
> // found : Null(null)
> // required: A.AuthToken with NotNull
> // b.notifyAdded()(null)
> // ^
>
> var bs: List[B] = Nil
> def add(b: B) = {
> bs :+= b
> b.notifyAdded()
> }
> }
>
> % scala Test
> Added B@3295cfbe
> Added B@1de58cb8
>
>

Patrik Andersson
Joined: 2009-11-16,
User offline. Last seen 42 years 45 weeks ago.
Re: "private class tunnel"
Why don't you invent a notification trait which the target of that notification implement, and then initialize the source of the notification with something that implements that trait? Plain old inversion of control.

On Mon, Jul 19, 2010 at 8:21 AM, HamsterofDeath <h-star [at] gmx [dot] de> wrote:
implicit friends :D

Paul Phillips schrieb:
> On Sun, Jul 18, 2010 at 09:48:21PM -0400, Brian Mosley wrote:
>
>> So, you're essentially saying that you need friend classes a la C++ or
>> Eiffel.  I don't think Scala supports this.
>>
>
> This is scala we're talking about.  It's always possible.
>
> I'm not saying this is the best way.  It's the first one I thought of,
> and has the bonus of being a useful application of NotNull, something I
> don't remember ever seeing before.
>
> // A.scala
> object A {
>   sealed trait AuthToken
>   private implicit object Auth extends AuthToken
> }
> class A {
>   import A._
>   var bs: List[B] = Nil
>   def add(b: B) = {
>     bs :+= b
>     b.notifyAdded()
>   }
> }
>
> // B.scala
> class B {
>   def notifyAdded()(implicit auth: A.AuthToken with NotNull): Unit = println("Added " + this)
> }
>
> // Test.scala
> object Test {
>   def main(args: Array[String]): Unit = {
>     val a = new A
>     a add new B
>     a add new B
>   }
> }
>
> // NoFriendOfMine.scala (doesn't compile, intentionally)
> class NoFriendOfMine {
>   // Things to try.
>   //
>   // 1) import A._ (or as-is)
>   // error: could not find implicit value for parameter auth: A.AuthToken with NotNull
>   //     b.notifyAdded()
>   //                  ^
>   // 2) implicit object Auth extends A.AuthToken
>   // error: illegal inheritance from sealed trait AuthToken
>   //   implicit object Auth extends A.AuthToken
>   //                                  ^
>   // 3) b.notifyAdded()(null)
>   // error: type mismatch;
>   //  found   : Null(null)
>   //  required: A.AuthToken with NotNull
>   //     b.notifyAdded()(null)
>   //                     ^
>
>   var bs: List[B] = Nil
>   def add(b: B) = {
>     bs :+= b
>     b.notifyAdded()
>   }
> }
>
> % scala Test
> Added B@3295cfbe
> Added B@1de58cb8
>
>


Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland