Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Philosophical question on collection reference types

Reply
Thread Tools

Philosophical question on collection reference types

 
 
Chris Uppal
Guest
Posts: n/a
 
      03-03-2007
Lew wrote:

> As I understand it, the established dogma is to use the widest type that
> does what you want. List is too wide for this, so use ArrayList.


Note of terminological difference: what you're calling wide is what I call the
narrowest type -- the one which conveys the least information.


> Like many other ideas, the oversimplification seems to stick in people's
> minds that one should "always use the interface". The real principle is
> to use the widest type that fits.


In this case, though, Patricia /can/ use List, since it supports all the
necessary operations. ArrayList would be overspecifying (or might be). The
information that is, or isn't, being communicated isn't really type-related[*]
at all, but is a quality-of-service aspect. It isn't enough just to be able to
do <something>, but the object must be able to do <something> with certain
performance guarantees.

-- chris
[*] "type" here being construed in the sense of Java's type system. It's
possible to imagine a type system where asymptotic performance bounds were part
of methods' type signatures.



 
Reply With Quote
 
 
 
 
Lew
Guest
Posts: n/a
 
      03-03-2007
Chris Uppal wrote:
> Note of terminological difference: what you're calling wide is what I call the
> narrowest type -- the one which conveys the least information.


So noted, and I was not being precise. My sense of "wide" means "encompasses
the largest number of subtypes". By rights I should have said "highest"
instead of "widest", thus conveying the usual depiction of top-rooted
inheritance hierarchies and conforming to the notion of "upcasting".

Good call.

-- Lew
 
Reply With Quote
 
 
 
 
Piotr Kobzda
Guest
Posts: n/a
 
      03-05-2007
Chris Uppal wrote:
> Lew wrote:


>> Like many other ideas, the oversimplification seems to stick in people's
>> minds that one should "always use the interface". The real principle is
>> to use the widest type that fits.


Or simply -- use the least specialized type that fits.


> In this case, though, Patricia /can/ use List, since it supports all the
> necessary operations. ArrayList would be overspecifying (or might be). The
> information that is, or isn't, being communicated isn't really type-related[*]
> at all, but is a quality-of-service aspect. It isn't enough just to be able to
> do <something>, but the object must be able to do <something> with certain
> performance guarantees.


>[*] "type" here being construed in the sense of Java's type system. It's
> possible to imagine a type system where asymptotic performance bounds were part
> of methods' type signatures.


Agreed. However, I see no problem with type system defined like that.
A lot of (less or more useful) "typologies" coexists in Java's type
system (are they all, for example Serializable semantics, really
type-related?), why then not to add that another one (i.e. performance
aspect) too? Especially when that matters, and may become a source of
not only poor quality of service, but even of denial of service (e.g.
system not responding in "reasonable" time...).

That type can be simply defined (the IndexedList from your previous post
is an example). But it holds obvious disadvantage, classes like
ArralList must additionally implement it to become useful.

We can also define that type "virtually" using type intersection --
which I can't point out important disadvantages for.


What's then the argument against using intersection type here?


BTW -- I've just explored a bit deeper my advice from previous post, and
it results in conclusion, that intersection type can be used even
simpler in that case, e.g. that way:

<L extends List<?> & RandomAccess> void processList(L list)

or, of course, when a concrete list elements type is know, that way:

<L extends List<String> & RandomAccess> void processList(L list)


Nevertheless, my previous parameterization with two type variables, may
still appear useful when we need additional constrains on list's element
types, or when exact return type of list is unknown, and we don't want
to lose any information about it from method's return type, e.g.:

<E, L extends List<E> & RandomAccess> L filter(L list) {
// ...
return list;
}

Although, usage of such a method is probably slightly limited (instead
of method-chaining and the like), it's /at least/ worth to be noted as
an alternative declaration.

Inconvenience here is when we want to have, for example, a generic
factory method like that:

<E, L extends List<E> & RandomAccess> L createRandomAccessList() {
return (L) new ArrayList<E>(); // unchecked cast
}

Which, despite of that ugly unchecked cast, seems to be useful at first,
and it even works as expected, but holds a small problem... We can not
directly pass its result as an input for another method which it should
be compatible with -- the following won't compile:

processList(createRandomAccessList());

That's because type inference takes place here, so without any
additional advice compiler fails with that.

Hopeless, while Java generics is implemented using type erasure (and
capture conversion, and so on...), we (I) can't even workaround it, i.e.
to make it working without explicitly provided type argument...


But let's beck to the original problem...

Don't you think, that in Patricia's particular case, /possibly/ neither
the use of List nor ArrayList is better than using intersection type of
List and RandomAccess?


piotr
 
Reply With Quote
 
Piotr Kobzda
Guest
Posts: n/a
 
      03-06-2007
Piotr Kobzda wrote:

> Inconvenience here is when we want to have, for example, a generic
> factory method like that:
>
> <E, L extends List<E> & RandomAccess> L createRandomAccessList() {
> return (L) new ArrayList<E>(); // unchecked cast
> }
>
> Which, despite of that ugly unchecked cast, seems to be useful at first,
> and it even works as expected, but holds a small problem...


Well. It's not a small problem here (and it's not /that/ problem in
fact), it's rather bigger one... Here is a mistake in my treatment of
second type parameter, not a generics implementation nor a compiler
fault. The ArrayList<E> is not valid substitute for all possible
intersection types of List<E> and RandomAccess, thus the code above is
simply incorrect.

> We can not
> directly pass its result as an input for another method which it should
> be compatible with -- the following won't compile:
>
> processList(createRandomAccessList());
>
> That's because type inference takes place here, so without any
> additional advice compiler fails with that.
>
> Hopeless, while Java generics is implemented using type erasure (and
> capture conversion, and so on...), we (I) can't even workaround it, i.e.
> to make it working without explicitly provided type argument...


However, it can be done correctly using factory object implementing the
following-like interface:

interface RandomAccessListFactory<E, L extends List<E> &
RandomAccess> {
L newList();
}

We can then create its implementation like that:

static <E> RandomAccessListFactory<E, ? extends List<E>>
defaultListFactory() {
return new RandomAccessListFactory<E, ArrayList<E>>() {
public ArrayList<E> newList() {
return new ArrayList<E>();
}
};
}

and then use it, that way:

processList(defaultListFactory().newList());

The compiler nicely infers all types as needed. (Notice no need for
explicit declaration of ArrayList beside the factory scope).


The above is wide extension, and possibly very far from, the point of
the original question. It simply shows, that working with intersection
types is not as straight forward as working with the regular Java types
(more, it still appears to me as a little abuse of the intersection
types), but it seams to be possible.

Of course, I'm still far from recommending it -- just wondering, how to
efficient work with that, and if it all is worth the effort?...


piotr
 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      03-06-2007
Piotr Kobzda wrote:

> That type can be simply defined (the IndexedList from your previous post
> is an example). But it holds obvious disadvantage, classes like
> ArralList must additionally implement it to become useful.
>
> We can also define that type "virtually" using type intersection --
> which I can't point out important disadvantages for.
>
>
> What's then the argument against using intersection type here?


Right now, I have no real argument against it -- the reason I didn't mention it
myself is that it simply didn't occur to me that you could express the dual
requirement in that way.

Besides the fact (unfortunate but true) that I tend to forget that intersection
types are available at all, I don't feel confident enough in my "feel" for what
knock-on effects a given declaration will have (especially a relatively
"advanced" one), to be able to adocate using or avoiding that approach. I
would be a good deal happier if intersection types could be declared as
"top-level" constuctions -- the way they are resticted to use in type bounds
makes me uneasy, but I don't yet know whether that unease is justified.

I want think about this some more, and do some experiments -- it's a good
chance to learn a bit...

-- chris


 
Reply With Quote
 
Daniel Pitts
Guest
Posts: n/a
 
      03-06-2007
On Mar 6, 9:24 am, "Chris Uppal" <(E-Mail Removed)-
THIS.org> wrote:
> Piotr Kobzda wrote:
> > That type can be simply defined (the IndexedList from your previous post
> > is an example). But it holds obvious disadvantage, classes like
> > ArralList must additionally implement it to become useful.

>
> > We can also define that type "virtually" using type intersection --
> > which I can't point out important disadvantages for.

>
> > What's then the argument against using intersection type here?

>
> Right now, I have no real argument against it -- the reason I didn't mention it
> myself is that it simply didn't occur to me that you could express the dual
> requirement in that way.
>
> Besides the fact (unfortunate but true) that I tend to forget that intersection
> types are available at all, I don't feel confident enough in my "feel" for what
> knock-on effects a given declaration will have (especially a relatively
> "advanced" one), to be able to adocate using or avoiding that approach. I
> would be a good deal happier if intersection types could be declared as
> "top-level" constuctions -- the way they are resticted to use in type bounds
> makes me uneasy, but I don't yet know whether that unease is justified.
>
> I want think about this some more, and do some experiments -- it's a good
> chance to learn a bit...
>
> -- chris


It seems that it would be a useful Java syntax to allow type
intersections in regular variable declarations.

public <E> void myFunction(List<E>&RandomAccess randomAccessList)
{
}

It would be especially useful for this type of use:
public void myFunction() {
Runnable&Comparable<?> myRunner = getNextRunner();
myRunner.run();
return myRunner.compareTo(getNextRunner());
}

Note that I use methods in both the Runnable interface and Comparable
interface.

I'm not sure I like the syntax, but it could be worse .

My examples may not seem useful, but imagine the power with custom
interfaces, rather than built in ones.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Philosophical question about C Phil Bradby C Programming 28 02-02-2010 01:10 PM
A philosophical question about const member function neel C++ 2 06-13-2009 11:41 PM
Collection problems (create Collection object, add data to collection, bind collection to datagrid) Řyvind Isaksen ASP .Net 1 05-18-2007 09:24 AM
void vs void* (philosophical question) Giannis Papadopoulos C Programming 18 07-10-2006 08:19 AM
Philosophical question: Template Method Dave Rahardja C++ 11 08-07-2003 11:30 AM



Advertisments