syntatic sugar IN keyword.

R

Roedy Green

I would like it if you could write:

if ( birthYear == 610
|| birthYear == 1791
|| birthYear == 1851
|| birthYear == 1872 ) )

as

if ( birthYear in { 610, 1791, 1851, 1872} )
or

if ( birthYear in SPECIAL_YEARS )

The compiler could be clever. If you said something like this:

if ( i in { 1 , 2 ,3 ,4, 6, 7, 8, 9 } )

It could generate code as

if ( 1 <= i && i <= 9 && i != 5 )

Or it could create a boolean array, or even a map for big lists.
--
Roedy Green Canadian Mind Products
http://mindprod.com
Refactor early. If you procrastinate, you will have
even more code to adjust based on the faulty design.
..
 
L

Lew

I would like it if you could write:

if ( birthYear == 610
|| birthYear == 1791
|| birthYear == 1851
|| birthYear == 1872 ) )

as

if ( birthYear in { 610, 1791, 1851, 1872} )
or

if ( birthYear in SPECIAL_YEARS )

The compiler could be clever. If you said something like this:

if ( i in { 1 , 2 ,3 ,4, 6, 7, 8, 9 } )

It could generate code as

if ( 1<= i&& i<= 9&& i != 5 )

Or it could create a boolean array, or even a map for big lists.

Set <Integer> birthYears = new HashSet <Integer> ();
birthYears.add( 610 );
birthYears.add( 1791 );
...

if ( birthYears.contains( someYear ))
{
...
}
 
R

Roedy Green

Set <Integer> birthYears = new HashSet <Integer> ();
birthYears.add( 610 );
birthYears.add( 1791 );

As is, that takes more code that the original, and will likely be
slower, unless the list is fairly long.

You might prune that back a little with:

Set <Integer> birthYears = new HashSet<Integer>( Arrays.asList( 610,
1791 ... ));

If we had the "in" syntactic sugar, the compiler or run-time could be
making the tradeoff when to use a linear search, a binary search, a
boolean array or a hash lookup.
 
M

markspace

The compiler could be clever. If you said something like this:

if ( i in { 1 , 2 ,3 ,4, 6, 7, 8, 9 } )

It could generate code as

if ( 1<= i&& i<= 9&& i != 5 )

Or it could create a boolean array, or even a map for big lists.

public static <T> boolean isIn( T val, T ... array ) {
Set<T> set = new HashSet<T>( Arrays.asList(array) );
return set.contains( val );
}

public static void main(String[] args) {
int i = 1;
System.out.println("i=1 isIn: "+ isIn( i, 5, 3, 2, 1 ) );
i = 4;
System.out.println("i=4 isIn: "+ isIn( i, 5, 3, 2, 1 ) );
}
 
L

Lew

As is, that takes more code that the original, and will likely be
slower, unless the list is fairly long.

If the list is fairly short, then any performance differences are not worth
considering.
You might prune that back a little with:

Set<Integer> birthYears = new HashSet<Integer>( Arrays.asList( 610,
1791 ... ));

If we had the "in" syntactic sugar, the compiler or run-time could be
making the tradeoff when to use a linear search, a binary search, a
boolean array or a hash lookup.

Hash lookup. It's faster where it counts and close enough where it doesn't.
 
N

Nigel Wade

I would like it if you could write:

if ( birthYear == 610
|| birthYear == 1791
|| birthYear == 1851
|| birthYear == 1872 ) )

as

if ( birthYear in { 610, 1791, 1851, 1872} )
or

Is there something wrong with:

switch(birthYear) {
case 610:
case 1791:
case 1851:
case 1872:
doSomething();
break;
default:
doSomethingElse();
break;
}
if ( birthYear in SPECIAL_YEARS )

Or use Ruby, that provides pretty much what you want:

if ( [610, 1791, 1851, 1872].include?(birthYear) )
doSomething
end

I wonder if Python can do the same.
The compiler could be clever. If you said something like this:

if ( i in { 1 , 2 ,3 ,4, 6, 7, 8, 9 } )

It could generate code as

if ( 1 <= i && i <= 9 && i != 5 )

Or it could create a boolean array, or even a map for big lists.

or it could just write your entire program for you. Then we'd all be out
of job. Be careful what you wish for.
 
T

Tom McGlynn

I would like it if you could write:

if ( birthYear == 610
     || birthYear == 1791
     || birthYear == 1851
     || birthYear == 1872 ) )

as

if ( birthYear in { 610, 1791, 1851, 1872} )
or

if ( birthYear in SPECIAL_YEARS )

The compiler could be clever. If you said something like this:

if ( i in { 1 , 2 ,3 ,4, 6, 7, 8, 9 }  )

It could generate code as

if ( 1 <= i && i <= 9 && i != 5 )

Or it could create a boolean array, or even a  map for big lists.

For some cases perhaps you could use something like

if (in(1,2,3,4,5,6,7,8,9).contains(i)) {...}

with a method

static Set in(Object... data) {
Set mySet = new HashSet();
for (Object element: data) mySet.add(element);
return mySet;
}

If you use this a lot you could have this in some Utility class and do
a
import static Utility.in;

That's pretty close to your original request. I think autoboxing will
take care of the primitives but I haven't tried this. You'd need to
be chary of
if (in(1,2,3...).contains(1.0)) ...

If there were a special syntax it would likely be easier for the
compiler to automatically extract constant <in> lists out of loops but
doing that manually shouldn't be too difficult. There would be harder
with

for (somebigloop) {
method1(x)
}

method1(x) {
if (in(1,2,3).contains(x)) ( ...}
}

where a special syntax would make it a lot easier for the compiler to
recognize the constant expression and compute the hash only one time
rather than for each loop, but in such a case probably the Set should
not be a local variable that needs to be recomputed, but a class
member.


Regards,
Tom McGlynn
 
A

Andreas Leitgeb

Nigel Wade said:
Is there something wrong with:
switch(birthYear) {
case 610:
case 1791:
case 1851:
case 1872:
doSomething();
break;
default:
doSomethingElse();
break;
}
Except that it's fugly? ... no, nothing.
or it could just write your entire program for you. Then we'd all be out
of job. Be careful what you wish for.

I do hope for you, that your tasks are more interesting than what a
compiler could rather easily do for you.
 
L

Lew

Tom said:
For some cases perhaps you could use something like

    if (in(1,2,3,4,5,6,7,8,9).contains(i)) {...}

with a method

    static Set in(Object... data) {
        Set mySet = new HashSet();
        for (Object element: data) mySet.add(element);
        return mySet;
    }

If you use this a lot you could have this in some Utility class and do
a
    import static Utility.in;

That's pretty close to your original request. I think autoboxing will
take care of the primitives but I haven't tried this.  You'd need to
be chary of
   if (in(1,2,3...).contains(1.0)) ...

If there were a special syntax it would likely be easier for the
compiler to automatically extract constant <in> lists out of loops but
doing that manually shouldn't be too difficult.  There would be harder
with

   for (somebigloop) {
       method1(x)
   }

   method1(x) {
        if (in(1,2,3).contains(x)) ( ...}
   }

where a special syntax would make it a lot easier for the compiler to
recognize the constant expression and compute the hash only one time
rather than for each loop, but in such a case probably the Set should
not be a local variable that needs to be recomputed, but a class
member.

Special syntax - costly change that provides slight compression of
code that you basically write only once per project anyway.

You can prevent recalculation of 'in()' results by passing the
returned 'Set' instead of recalculating it.

void method1( Foo x, Set <Foo> inset )
{
if ( inset.contains( x ))
{ ..., }
}

which seems silly. Just create immutable 'Set's of what you want to
model as sets, and use 'Set#contains()' to model containment within a
set.

void methodThatNoLongerNeedsMethod1( Foo x )
{
final Set <Foo> inset = Collections.unmodifiableSet( in( foo0,
foo1, foo2, foo3 ));
while ( reallyLongLastingCondition() )
{
if ( inset.contains( x ))
{ ... }
}
}

Depending on your logic, 'inset' can be local, instance or class
scope. Depending on the number of loop iterations, the use of a
'HashSet' under the hood can really help performance even for fairly
small sets.

This is not a verbose idiom, certainly not by Java standards.
 
T

Tom McGlynn

Special syntax - costly change that provides slight compression of
code that you basically write only once per project anyway.

You can prevent recalculation of 'in()' results by passing the
returned 'Set' instead of recalculating it.

  void method1( Foo x, Set <Foo> inset )
  {
    if ( inset.contains( x ))
    { ..., }
  }

which seems silly.  Just create immutable 'Set's of what you want to
model as sets, and use 'Set#contains()' to model containment within a
set.

 void methodThatNoLongerNeedsMethod1( Foo x )
 {
   final Set <Foo> inset = Collections.unmodifiableSet( in( foo0,
foo1, foo2, foo3 ));
   while ( reallyLongLastingCondition() )
   {
     if ( inset.contains( x ))
     { ... }
   }
 }

Depending on your logic, 'inset' can be local, instance or class
scope.  Depending on the number of loop iterations, the use of a
'HashSet' under the hood can really help performance even for fairly
small sets.

This is not a verbose idiom, certainly not by Java standards.

It may not be appropriate for the invoking method to know the set of
alternatives -- they (and even the notion that there is some specific
list of alternatives used by the invoked method) may be fully
encapsulated in the invoked method which may be in some other class.
So I don't think Lew's approach of having the invoker know the
alternatives addresses the efficiency issue generally (in the
mathematical sense). However there are several idioms for
initializing the Set which avoids having to code an explicit add for
each element -- which does look pretty clumsy imho. Given that, I'd
generally (in the common usage sense) agree with Lew that it's
typically straightforward to find some way to use Set.contains such
that the benefit of special syntax is limited.

Regards,
Tom McGlynn
 
L

Lew

Tom said:
It may not be appropriate for the invoking method to know the set of
alternatives -- they (and even the notion that there is some specific
list of alternatives used by the invoked method) may be fully
encapsulated in the invoked method which may be in some other class.

I'll get back to this valid point.
So I don't think Lew's approach of having the invoker know the
alternatives addresses the efficiency issue generally (in the
mathematical sense). However there are several idioms for

You're absolutely correct. I aimed only to show that there was at least one
place where you could obviate the problem, not to show a universal solution
even were there such a thing. As one typical idiom involving 'contains()' it
does demonstrate that existing Java code can already be reasonably compact in
this area.

One assumes in this group an audience who can generalize "there is a solution"
to "here's one that applies to my situation", not just parrot what they see on
Usenet. Nor do I presume here to provide a final answer - only one case.
initializing the Set which avoids having to code an explicit add for
each element -- which does look pretty clumsy imho. Given that, I'd
generally (in the common usage sense) agree with Lew that it's
typically straightforward to find some way to use Set.contains such
that the benefit of special syntax is limited.

One should never construe a post in this forum to contravene otherwise
unmentioned best practices.

Others in this thread had already alluded to
'new HashSet<Foo>( Arrays.asList( foo0, foo1, foo2, foo3, ... ))',
for example. Where one wants to get more verbose, as in the case Tom brought
up (full encapsulation of the logic in a method), one is doing it for a reason
outside the use of some fancy new 'in' syntax. Whatever 'in' would solve is
simply pushed down into that encapsulating method, where the matter of
existing Java idioms once again pertains.

Even if 'in' were deemed valuable enough to enter the language, as other
dubious idioms have been, you'd still need to know how to do it until the
feature enters, and how do to it when the feature's coverage isn't enough.

We face this now with 'enum'. In rare circumstances 'enum' isn't enough, and
it's worth leaving the compiler express lane to create one's own type-safe
enumeration class just like we used to back in Java 1.4 and earlier. It's
like using carbon paper when you're used to a photocopier - sure, it's messy,
but it works.
 
J

Jim Janney

Roedy Green said:
I would like it if you could write:

if ( birthYear == 610
|| birthYear == 1791
|| birthYear == 1851
|| birthYear == 1872 ) )

as

if ( birthYear in { 610, 1791, 1851, 1872} )
or

if ( birthYear in SPECIAL_YEARS )

The compiler could be clever. If you said something like this:

if ( i in { 1 , 2 ,3 ,4, 6, 7, 8, 9 } )

It could generate code as

if ( 1 <= i && i <= 9 && i != 5 )

Or it could create a boolean array, or even a map for big lists.

There's a BitSet class you could use, but it's not space-efficient for
sparse data.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top