My favorites | Sign in
Project Home Wiki Issues Source
READ-ONLY: This project has been archived. For more information see this post.
Search
for
  Advanced search   Search tips   Subscriptions
Issue 14: PROPOSAL: access enum constructor parameters with == operator
1 person starred this issue and may be notified of changes. Back to list
 
Project Member Reported by she...@coolpage.com, Mar 7, 2010
This was originally reported as a proposal for the HaXe 2.04 language:

https://code.google.com/p/haxe/issues/detail?id=102

My comments from that issue have been copied here, so to the extent that
Copute may support HaXe as an output target, then the context of the
proposal relative to HaXe is recorded.
Mar 7, 2010
Project Member #1 she...@coolpage.com
The constructor parameters for an enum in HaXe are currently only accessible in a switch:

http://haxe.org/ref/enums  (section "Switch with Constructor Parameters")

"...Using switch is the only possible way to access the enum constructors parameters..."

I propose they also be accessible with the == operator, as I am planning for Copute:

http://copute.com/dev/docs/Copute/ref/class.html#Enumerated_Inheritance

The reason this is important is because otherwise there is no way to access the
constructor parameters without maintaining unnecessary boilerplate code for a
function that can return the parameters, and this function will be hampered by having
to amalgamate all the different possibilities for constructor parameters into one
return type.

For example:

enum Color3 {
   red;
   green;
   blue;
   grey( v : Int );
   rgb( r : Int, g : Int, b : Int );
   huv( h : Int, u : Int, v : Int );
   alpha( a : Int, col : Color3 );
}

Let's say I want to get the value of Color3 after testing if two of them are equal,
then with my proposal:

var c1 : Color3 = rgb( a, b, c )
var c2 : Color3 = rgb( d, e, f )

if( rgb == c2 )
{
   // c2 is an rgb
   // c2's r is not considered, etc
}

if( rgb( r, g, b ) == c2 )
{
   // c2 is an rgb
   // r, g, b are now variables
   // and r is equal to c2's r, etc
}

if( c1 == rgb && c1( r, g, b ) == c2 )
{
   // c1 and c2 are rgb
   // r, g, b are now variables
   // and r MUST BE equal to c2's r, etc
}

if( c1( r, g, b ) == c2 )
{
   // c1 and c2 are rgb or huv
   // r, g, b are now variables
   // and r MUST BE equal to c2's r or h, etc
}

if( c1( r1, g1, b1 ) == c2( r2, g2, b2 ) )
{
   // c1 and c2 are rgb or huv
   // r1, g1, b1, r2, g2, b2 are now variables
   // and r1 may or may not equal r2, etc
}

Whereas, with HaXe, we have to build boilerplate verbose switch, and verbose logic
for comparing the constructor parameters:

if( rgb == c2 )
{
   // c2 is an rgb
   // c2's r is not considered, etc
}

if( rgb == c2 )
{
   // c2 is an rgb
   var vals2 = values( c2 )
   // and vals2.r is equal to c2's r, etc
}

var vals1 = values( c1 ), vals2 = values( c2 )
if( c1 == rgb && c1 == c2 && vars1.r == vals2.r && vars1.g == vals2.g && vars1.b ==
vals2.b )
{
   // c1 and c2 are rgb
   // and vals1.r IS equal to c2's r, etc
}

var vals1 = values( c1 ), vals2 = values( c2 )
if( c1 == c2 && vars1.r == vals2.r && vars1.g == vals2.g && vars1.b == vals2.b )
{
   // c1 and c2 are rgb or huv
   // and vals1.r IS equal to c2's r or h, etc
}

if( (c1 == rgb && c2 == rgb) || (c1 == huv && c2 == huv) )
{
   // c1 and c2 are rgb or huv
   var vals1 = values( c1 ), vals2 = values( c2 )
   // and vals1.r may or may not equal vals2.r, etc
}

function values( c : Color3 ) : {v : Int, r : Int, g : Int, b : Int, a : Int, col :
Color3}
{
   switch( c )
   {
      case red: return {v : null, r : null, g : null, b : null, a : null, col : null}
      case green: return {v : null, r : null, g : null, b : null, a : null, col : null}
      case blue: return {v : null, r : null, g : null, b : null, a : null, col : null}
      case grey( v ): return {v : v, r : null, g : null, b : null, a : null, col : null}
      case rgb( r, g, b ): return {v : null, r : r, g : g, b : b, a : null, col : null}
      case huv( h, u, v ): return {v : null, r : h, g : u, b : v, a : null, col : null}
      case alpha( a, col ): return {v : null, r : r, g : g, b : b, a : a, col : col}
   }
}
Mar 7, 2010
Project Member #2 she...@coolpage.com
The example in a file.
temp2.txt
3.5 KB   View   Download
Mar 7, 2010
Project Member #3 she...@coolpage.com
Note that for this scenario:

if( c1( r, g, b ) == c2 )

If huv and rgb instead had different type(s) for their constructor parameter(s), then
the compiler should give an error "The enum comparison is ambiguous on constructor
parameter type(s)".
Mar 7, 2010
Project Member #4 she...@coolpage.com
Also to be complete, exclusion boilerplate should be eliminated, for example I propose:

if( c1 == Color3( r, g, b ) )
{
   // c1 is a rgb or huv
   // r, g, b are variables equal to c1's constructor parameters
}

In HaXe, this would currently require an explicit exclusion boilerplate which must be
edited each time we add a new constructor to the enum:

if( c1 != red && c1 != green && c1 != blue && c1 != grey && c1 != alpha )
{
   // c1 is a rgb or huv
   v = values( c1 )
   // v.r, v.g, v.b are variables equal to c1's constructor parameters
}
Mar 7, 2010
Project Member #5 she...@coolpage.com
Also I propose exclusion should be possible with default:

switch( c1 )
{
   case red, green, blue:
   case grey( v ):
   case alpha( a, col ):
   default( r, g, b ):
      // c1 is a rgb or huv
      // r, g, b are variables equal to c1's constructor parameters

}

I presume this can be done in HaXe currently:

switch( c1 )
{
   default:
   case rgb( r, g, b ), huv( r, g, b ):
      // c1 is a rgb or huv
      // r, g, b are variables equal to c1's constructor parameters

}

If HaXe can only do instead as follows, then sometimes code will be unnecessarily
duplicated:

switch( c1 )
{
   default:
   case rgb( r, g, b ):
      // c1 is a rgb
      // r, g, b are variables equal to c1's constructor parameters
   case huv( h, u, v ):
      // c1 is a huv
      // h, u, v are variables equal to c1's constructor parameters

}
Mar 7, 2010
Project Member #6 she...@coolpage.com
I assume currently in HaXe that c1 == c2 or c1 != c2 does not compare the constructor
parameters, only compares the type of the constructor (i.e. type is red, green, rgb,
etc)?

If not, then I am proposing it should work that way.

In my proposal those are respectively equivalent to c1( _, __, ___ ) == c2( ____,
_____, ______ ) and !(c1( _, __, ___ ) == c2( ____, _____, ______ )).

And in my proposal, when it is desired that the constructor parameters are compared,
c1( r, g, b ) == c2 and !(c1( r, g, b ) == c2) respectively.
Mar 7, 2010
Project Member #7 she...@coolpage.com
So let me summarize the syntax and semantics of the proposal.  Actually it applies to
the != operator also:

op :=
   ==
   !=

eexpr :=
   et1 params1? op et2 params2?

et1 means the type given by name of constructor, e.g. red, green, gray, rgb, etc

et1 op et2 && ((exists params1 && exists params2) || (!exists params1 && !exists
params2) || (exists params1 && each params1 op each et2 param) || (exists params2 &&
each params2 op each et1 param))

If the enum type is used for et1 or et2 (e.g. Color3), then this means to expand it
to the equivalent exclusion types expression.

If the params* exist and the above expression is true, then the params* will have
non-null values, else they will have null values if expression is false.  If we
require that this expression is only possible for:

if eexpr expr
while eexpr expr

Then params* will only have scope within expr, and thus will never be null.

============

And I have proposed that exclusion constructor parameters be allowed on default in a
switch.
Mar 7, 2010
Project Member #8 she...@coolpage.com
For the (exists params1 && exists params2) case, then the scope of the non-null
params* will be in both expr1 and expr2 in:

if eexpr expr1 else expr2
Mar 7, 2010
Project Member #9 she...@coolpage.com
Also always for case in switch and only when it does not cause ambiguity for the
proposed default in switch and for == and != operators, I propose it should be
allowed to access only some (from left-to-right) constructor parameters (even if they
were not ? optional).

This will reduce code verbosity, and eliminate the creation of unused variables.
Feb 6, 2011
Project Member #10 she...@coolpage.com
Note Scala also allows comparing existing instances to the constructor parameters, which seems to be more confusing than it worth:

http://creativekarma.com/ee.php/weblog/comments/my_verdict_on_the_scala_language/

"The pattern matching adds a new level of confusion. The pattern ClassName(var1,var2) is like instanceOf on steroids, because it looks not just at the name of the class but also at the constructor arguments that were used to create the specific object (two arguments in this example). But that pattern can mean four different things depending on whether var1 and/or var2 are defined or not. If a variable is defined, then the pattern only matches if the value used to construct the object matches the current value of the variable. If the variable is not defined, then the pattern always matches on that constructor field and a local variable of that name is created and assigned the value that was used when the object was constructed. Determining if a particular variable is defined in a particular scope can be a challenge, especially since it might have been defined by another pattern."
Feb 6, 2011
Project Member #11 she...@coolpage.com
Regarding Comment 0, I think the '==' should be changed to '===', because as I understand the current proposed semantics of the Copute grammar in Issue 43, '==' compares the reference (i.e. pointing to same instance), and '===' will compare the contents of two separate instances.

Powered by Google Project Hosting