Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #31092 > unrolled thread

Re: "null", polymorphism and TCO

Started byKevin McMurtrie <mcmurtrie@pixelmemory.us>
First post2015-02-08 23:06 -0800
Last post2015-02-10 12:51 -0600
Articles 5 — 3 participants

Back to article view | Back to comp.lang.java.programmer

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: "null", polymorphism and TCO Kevin McMurtrie <mcmurtrie@pixelmemory.us> - 2015-02-08 23:06 -0800
    Re: "null", polymorphism and TCO Marcel Mueller <news.5.maazl@spamgourmet.org> - 2015-02-09 11:36 +0100
      Re: "null", polymorphism and TCO Kevin McMurtrie <mcmurtrie@pixelmemory.us> - 2015-02-09 20:35 -0800
        Re: "null", polymorphism and TCO Marcel Mueller <news.5.maazl@spamgourmet.org> - 2015-02-10 10:37 +0100
          Re: "null", polymorphism and TCO Joshua Cranmer 🐧 <Pidgeot18@verizon.invalid> - 2015-02-10 12:51 -0600

#31092 — Re: "null", polymorphism and TCO

FromKevin McMurtrie <mcmurtrie@pixelmemory.us>
Date2015-02-08 23:06 -0800
SubjectRe: "null", polymorphism and TCO
Message-ID<mcmurtrie-19F4EE.23064308022015@news.sonic.net>
A simple hasNext() method is easier.

What I really dislike is the JRE implementations of BlockingDeque and 
BlockingQueue.  There's no "close" and adding null is forbidden so it's 
a pain in the ass to terminate a queue and its waiters.


If Oracle ever optimizes away the String(String) constructor it's going 
to break a lot of code where I have to terminate String queues with 
something like this:

static final String endOfQueue= new String("end");

 ...

while ((item= queue.take()) != endOfQueue)
{
 ...
}
queue.put(endOfQueue);



When it's OK to import libraries I use my own queue that has a close() 
method.




In article <null-20150208185452@ram.dialup.fu-berlin.de>,
 ram@zedat.fu-berlin.de (Stefan Ram) wrote:

>   A book said that one needed null to mark the end of a linked
>   list:
> 
> class Entry { java.lang.String text; Entry next; };
> 
> public final class Main
> { public static void main( final java.lang.String[] args )
>   { Entry first = new Entry(); first. text = "first";
>     Entry second = new Entry(); second.text = "second";
>     first.next = second;
>     Entry last = new Entry(); last.text = "third";
>     second.next = last;
>     for
>     ( Entry current = first; current != null;
>       current = current.next )
>     java.lang.System.out.println( current.text ); }}
> 
>   This prints:
> 
> first
> second
> third
> 
> 
>   Neither null nor java.util.Optional is needed when one
>   is using polymorphism, i.e., real OOP. We just need to say 
>   that an entry with a next entry is a different type than
>   an entry without a next entry. No »null«, no »Optional«,
>   just polymorphism!
> 
> abstract class Entry 
> { java.lang.String text; 
>   abstract void accept
>   ( java.util.function.Consumer< java.lang.String >consumer );  }
> 
> class TerminationEntry extends Entry 
> { void accept
>   ( java.util.function.Consumer< java.lang.String >consumer )
>   { consumer.accept( text ); } };
> 
> class ContinuationEntry extends Entry 
> { Entry next; void accept
>   ( java.util.function.Consumer< java.lang.String >consumer )
>   { consumer.accept( text ); next.accept( consumer ); }};
> 
> public final class Main
> { public static void main( final java.lang.String[] args )
>   { ContinuationEntry first = new ContinuationEntry();
>     first. text = "first";
>     ContinuationEntry second = new ContinuationEntry();
>     second.text = "second"; first.next  = second;
>     TerminationEntry  last = new TerminationEntry();
>     last.text = "third"; second.next = last;
>     first.accept( java.lang.System.out::println ); }}
> 
>   This, too, prints:
> 
> first
> second
> third
> 
>   But now, there is a case of recursion (in the method
>   »accept« of the class »ContinuationEntry«). But it is
>   tail recursion. Now, this might be too far fetched,
>   but insofar one might say that proper OOP needs TCO
>   and hope that one day Oracle will find this out!
> 
>   From a practical point of view, the null solution
>   seems to be a kind of optimization: When one wants
>   to append to a TerminationEntry, one first needs to
>   replace it by a ContinuationEntry. This wastes more
>   resources than just overwriting a null value.

-- 
I will not see posts from astraweb, theremailer, dizum, or google
because they host Usenet flooders.

[toc] | [next] | [standalone]


#31095

FromMarcel Mueller <news.5.maazl@spamgourmet.org>
Date2015-02-09 11:36 +0100
Message-ID<mba2ip$3nr$1@gwaiyur.mb-net.net>
In reply to#31092
On 09.02.15 08.06, Kevin McMurtrie wrote:
> If Oracle ever optimizes away the String(String) constructor it's going
> to break a lot of code where I have to terminate String queues with
> something like this:
>
> static final String endOfQueue= new String("end");
>
>   ...
>
> while ((item= queue.take()) != endOfQueue)
> {
>   ...
> }
> queue.put(endOfQueue);

The reference equality trick (instead of null) will work with /any/ 
other object as well. There is no need for String(String).


Marcel

[toc] | [prev] | [next] | [standalone]


#31103

FromKevin McMurtrie <mcmurtrie@pixelmemory.us>
Date2015-02-09 20:35 -0800
Message-ID<mcmurtrie-338D50.20354409022015@news.sonic.net>
In reply to#31095
In article <mba2ip$3nr$1@gwaiyur.mb-net.net>,
 Marcel Mueller <news.5.maazl@spamgourmet.org> wrote:

> On 09.02.15 08.06, Kevin McMurtrie wrote:
> > If Oracle ever optimizes away the String(String) constructor it's going
> > to break a lot of code where I have to terminate String queues with
> > something like this:
> >
> > static final String endOfQueue= new String("end");
> >
> >   ...
> >
> > while ((item= queue.take()) != endOfQueue)
> > {
> >   ...
> > }
> > queue.put(endOfQueue);
> 
> The reference equality trick (instead of null) will work with /any/ 
> other object as well. There is no need for String(String).
> 
> 
> Marcel

An enum named something like EOF is, of course, much better but it can't 
be put into BlockingDeque<String>.

Every once in a while I hear talk of adding automatic String interning 
or optimizing away the String(String) constructor such that this becomes 
true:
new String("foo") == "foo"

It would surely break tons of code.  Not only would it break unique 
tokens, but it would break WeakHashMap<String, ?> too.

-- 
I will not see posts from astraweb, theremailer, dizum, or google
because they host Usenet flooders.

[toc] | [prev] | [next] | [standalone]


#31104

FromMarcel Mueller <news.5.maazl@spamgourmet.org>
Date2015-02-10 10:37 +0100
Message-ID<mbcjh4$388$1@gwaiyur.mb-net.net>
In reply to#31103
On 10.02.15 05.35, Kevin McMurtrie wrote:
> An enum named something like EOF is, of course, much better but it can't
> be put into BlockingDeque<String>.

Since Java uses type erasure I would not bet on it. With some cast to a 
non-generic container you will probably succeed. But you will also 
dislike the exception when extracting it as a String.


> Every once in a while I hear talk of adding automatic String interning
> or optimizing away the String(String) constructor such that this becomes
> true:
> new String("foo") == "foo"
>
> It would surely break tons of code.  Not only would it break unique
> tokens, but it would break WeakHashMap<String, ?> too.

Probably no one will ever remove an explicit constructor call.

But this does not apply if you assign string constants. E.g.

   String s1 = "foo";
   s1 == "foo" // might be true

Probably it will be true in most cases since the Java compiler will 
likely not create two instances of the same constant. But I am unsure 
what happens if the two lines are in different java or jar files. I 
think it is simply undefined behavior.

So in your example
   static final String endOfQueue= new String();
should do the job as well.


This is similar to the old style typesafe enum pattern:

final class MyEnum
{ private final int Value;
   private MyEnum(int value) { Value = value; }

   public static final MyEnum AVALUE = new MyEnum(1);
   public static final MyEnum ANOTHERVALUE = new MyEnum(2);
   ...
}

This commonly used pattern is stupid. The integer is entirely superfluous.

final class MyEnum
{ private MyEnum() {}

   public static final MyEnum AVALUE = new MyEnum();
   public static final MyEnum ANOTHERVALUE = new MyEnum();
   ...
}

This will do the job as well.

Of course, the new type safe enums in Java are more convenient.


Marcel

[toc] | [prev] | [next] | [standalone]


#31106

FromJoshua Cranmer 🐧 <Pidgeot18@verizon.invalid>
Date2015-02-10 12:51 -0600
Message-ID<mbdjti$492$1@dont-email.me>
In reply to#31104
On 2/10/2015 3:37 AM, Marcel Mueller wrote:
> But this does not apply if you assign string constants. E.g.
>
>    String s1 = "foo";
>    s1 == "foo" // might be true
>
> Probably it will be true in most cases since the Java compiler will
> likely not create two instances of the same constant. But I am unsure
> what happens if the two lines are in different java or jar files. I
> think it is simply undefined behavior.

The JLS mandates that all compile-time string constants (this includes 
"fo" + "o") are references to their appropriate interned string, so it's 
guaranteed that "foo" == "foo".intern().

-- 
Beware of bugs in the above code; I have only proved it correct, not 
tried it. -- Donald E. Knuth

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web