www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - cannot cast

reply "Namespace" <rswhite4 googlemail.com> writes:
I finished my Ref/NotNull struct, but i've got a problem:
If i try to cast the class, which should implicit convert to 
Ref!(Type) with alias this, i get the following error message:
"cannot cast a1.getRef("Ref.d",72u) of type Ref!(A) to type 
RefTest.Ref.__unittest1.B"

Can someone explain that to me or help me with it?
It seems that alias this replacement isn't smart enough to 
distinguish, if it has to convert.

[code]
import std.conv : to;

struct Ref(T : Object) {
private:
	 T _obj;

public:
	 disable
	this();// { }

	 disable
	this(typeof(null));// { }

	this(T obj) {
		assert(obj !is null, "Object is null!");

		this._obj = obj;
	}

	 property
	inout(T) access() inout {
		assert(this._obj !is null, "Access: Object is null!");

		return this._obj;
	}

	//alias access this; // print "Stackoverflow" or "recursive 
expansion"
}

mixin template TRef(T : Object) {
	final Ref!(T) getRef(string file = __FILE__, size_t line = 
__LINE__) in {
		assert(this !is null, "Object is null!   " ~ file ~ " in Line " 
~ to!(string)(line) ~ ".");
	} body {
		return Ref!(T)(this);
	}
	
	final Ref!(const T) getRef(string file = __FILE__, size_t line = 
__LINE__) const in {
		assert(this !is null, "Object is null!   " ~ file ~ " in Line " 
~ to!(string)(line) ~ ".");
	} body {
		return Ref!(const T)(this);
	}

	alias getRef this;
}

unittest {

	class A {
		mixin TRef!(A);
	}

	class B : A { }

	class C : B { }

	A a1 = new B();
	A a2 = new C();

	B b1 = cast(B) a1; // line 72
}
Apr 28 2012
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Saturday, 28 April 2012 at 14:21:32 UTC, Namespace wrote:
 I finished my Ref/NotNull struct, but i've got a problem:
 If i try to cast the class, which should implicit convert to 
 Ref!(Type) with alias this, i get the following error message:
 "cannot cast a1.getRef("Ref.d",72u) of type Ref!(A) to type 
 RefTest.Ref.__unittest1.B"

 Can someone explain that to me or help me with it?
 It seems that alias this replacement isn't smart enough to 
 distinguish, if it has to convert.

 [code]
 import std.conv : to;

 struct Ref(T : Object) {
 private:
 	 T _obj;

 public:
 	 disable
 	this();// { }

 	 disable
 	this(typeof(null));// { }

 	this(T obj) {
 		assert(obj !is null, "Object is null!");

 		this._obj = obj;
 	}

 	 property
 	inout(T) access() inout {
 		assert(this._obj !is null, "Access: Object is null!");

 		return this._obj;
 	}

 	//alias access this; // print "Stackoverflow" or "recursive 
 expansion"
 }

 mixin template TRef(T : Object) {
 	final Ref!(T) getRef(string file = __FILE__, size_t line = 
 __LINE__) in {
 		assert(this !is null, "Object is null!   " ~ file ~ " in Line 
 " ~ to!(string)(line) ~ ".");
 	} body {
 		return Ref!(T)(this);
 	}
 	
 	final Ref!(const T) getRef(string file = __FILE__, size_t line 
 = __LINE__) const in {
 		assert(this !is null, "Object is null!   " ~ file ~ " in Line 
 " ~ to!(string)(line) ~ ".");
 	} body {
 		return Ref!(const T)(this);
 	}

 	alias getRef this;
 }

 unittest {

 	class A {
 		mixin TRef!(A);
 	}

 	class B : A { }

 	class C : B { }

 	A a1 = new B();
 	A a2 = new C();

 	B b1 = cast(B) a1; // line 72
 }
Trying to fix it with an opCast in Ref ended in an infinity loop...
Apr 28 2012
parent "Namespace" <rswhite4 googlemail.com> writes:
Trying with
	U opCast(U : Object)() {
		return new U();
	}

work fine. It isn't a solution, but i don't understand why this 
works and the following not:

	U opCast(U : Object)() {
		return cast(U) this._obj;
	}

I hope really some of you can explain that to me and help me to 
fix it.
And forgive me the old senseless thread title. ;)
Apr 28 2012
prev sibling parent reply "Jesse Phillips" <jessekphillips+D gmail.com> writes:
On Saturday, 28 April 2012 at 14:21:32 UTC, Namespace wrote:
 I finished my Ref/NotNull struct, but i've got a problem:
 If i try to cast the class, which should implicit convert to 
 Ref!(Type) with alias this, i get the following error message:
 "cannot cast a1.getRef("Ref.d",72u) of type Ref!(A) to type 
 RefTest.Ref.__unittest1.B"
I would consider this a bug: http://d.puremagic.com/issues/show_bug.cgi?id=8001
Apr 29 2012
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Sunday, 29 April 2012 at 14:40:55 UTC, Jesse Phillips wrote:
 On Saturday, 28 April 2012 at 14:21:32 UTC, Namespace wrote:
 I finished my Ref/NotNull struct, but i've got a problem:
 If i try to cast the class, which should implicit convert to 
 Ref!(Type) with alias this, i get the following error message:
 "cannot cast a1.getRef("Ref.d",72u) of type Ref!(A) to type 
 RefTest.Ref.__unittest1.B"
I would consider this a bug: http://d.puremagic.com/issues/show_bug.cgi?id=8001
Oh, that could explain a lot. Some workaround until now?
Apr 29 2012
parent reply "Namespace" <rswhite4 googlemail.com> writes:
Can anyone tell me, why the this code

[code]
module RefTest.Ref;

import std.stdio : writeln;
import std.conv : to, toImpl;

T const_cast(T : Object)(const T obj) {
	return cast(T) obj;
}

struct Ref(T : Object) {
private:
	 T _obj;

public:
	 disable
	this();// { }

	 disable
	this(typeof(null));// { }

	this(T obj) {
		assert(obj !is null, "Object is null!");

		this._obj = obj;
	}

	 property
	inout(T) access() inout {
		assert(this._obj !is null, "Access: Object is null!");

		return this._obj;
	}

	//alias access this; // dann kommt "Stackoverflow" oder 
"recursive expansion"
}

mixin template TRef(T : Object) {
	final Ref!(T) getRef(string file = __FILE__, size_t line = 
__LINE__) in {
		assert(this !is null, "Object is null!   " ~ file ~ " in Line " 
~ to!(string)(line) ~ ".");
	} body {
		return Ref!(T)(this);
	}
	
	final Ref!(const T) getRef(string file = __FILE__, size_t line = 
__LINE__) const in {
		assert(this !is null, "Object is null!   " ~ file ~ " in Line " 
~ to!(string)(line) ~ ".");
	} body {
		return Ref!(const T)(this);
	}

	U opCast(U : Object)() {
		return *(cast(U*) &this);
	}

	alias getRef this;
}

unittest {
	bool instanceof(T : Object, U : Object)(const Ref!U obj) {
		//return const_cast(obj.access).toString() == 
typeid(T).toString();
		const U o = obj.access;

		return const_cast(o).toString() == typeid(T).toString();
	}

	class A {
		mixin TRef!(A);
	}

	class B : A { }

	class C : B { }

	A a1 = new B();
	A a2 = new C();

	assert(instanceof!(A)(a1) == false);
	assert(instanceof!(B)(a1));
	assert(instanceof!(C)(a1) == false);

	writeln(a1);

	B b1 = cast(B) a1;

	writeln(b1);

	writeln();
}
[/code]

fails with:

[quote]
Fehler	3	instantiated from here: 
instanceof!(A,A)	D:\D\VisualD\Visual Studio 
2010\Projects\RefTest\RefTest\Ref.d	76
	
Fehler	2	Error: template instance RefTest.Ref.const_cast!(A) 
error instantiating	D:\D\VisualD\Visual Studio 
2010\Projects\RefTest\RefTest\Ref.d	62
	
Fehler	4	Error: template instance 
RefTest.Ref.__unittest1.instanceof!(A,A) error 
instantiating	D:\D\VisualD\Visual Studio 
2010\Projects\RefTest\RefTest\Ref.d	76	

Fehler	1	Error: function 
RefTest.Ref.__unittest1.A.TRef!(A).opCast!(A).opCast () is not 
callable using argument types ()	D:\D\VisualD\Visual Studio 
2010\Projects\RefTest\RefTest\Ref.d	7	
[/quote]

? Sounds like a bug.
May 02 2012
parent reply "Namespace" <rswhite4 googlemail.com> writes:
Other, shorter example:

[code]
import std.stdio, std.traits;

class A {
	int val;

	alias val this;
	
	T opCast(T : Object)() {
		writeln("FOO");
		
		return to!(T)(this);
	}
}

class B : A {

}

T to(T : Object, U : Object)(const U obj) {
	return *(cast(T*) &obj);
}

T const_cast(T)(const T obj) {
	return cast(T) obj;
}

void main () {
	A a = new B();
	a.val = 42;
	
	writefln("a.val: %d", a.val);

	B* b = cast(B*) &a;
	writefln("*b.val: %d", b.val);

	B b1 = to!(B)(a);
	writefln("b1.val: %d", b1.val);
	
	B b2 = cast(B) a;
	writefln("b2.val: %d", b2.val);
	
	const B b3 = cast(B) a;
	
	B b4 = const_cast(b3);
}
[/code]

print:

alias_this_impl.d(24): Error: function 
alias_this_impl.A.opCast!(B).opCast () is
  not callable using argument types ()
alias_this_impl.d(44): Error: template instance 
alias_this_impl.const_cast!(B) e
rror instantiating

I'm not very skillful in such "template" stories. Maybe someone 
can help me?
May 02 2012
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Wednesday, 2 May 2012 at 22:38:36 UTC, Namespace wrote:
 Other, shorter example:

 [code]
 import std.stdio, std.traits;

 class A {
 	int val;

 	alias val this;
 	
 	T opCast(T : Object)() {
 		writeln("FOO");
 		
 		return to!(T)(this);
 	}
 }

 class B : A {

 }

 T to(T : Object, U : Object)(const U obj) {
 	return *(cast(T*) &obj);
 }

 T const_cast(T)(const T obj) {
 	return cast(T) obj;
 }

 void main () {
 	A a = new B();
 	a.val = 42;
 	
 	writefln("a.val: %d", a.val);

 	B* b = cast(B*) &a;
 	writefln("*b.val: %d", b.val);

 	B b1 = to!(B)(a);
 	writefln("b1.val: %d", b1.val);
 	
 	B b2 = cast(B) a;
 	writefln("b2.val: %d", b2.val);
 	
 	const B b3 = cast(B) a;
 	
 	B b4 = const_cast(b3);
 }
 [/code]

 print:

 alias_this_impl.d(24): Error: function 
 alias_this_impl.A.opCast!(B).opCast () is
  not callable using argument types ()
 alias_this_impl.d(44): Error: template instance 
 alias_this_impl.const_cast!(B) e
 rror instantiating

 I'm not very skillful in such "template" stories. Maybe someone 
 can help me?
Solved with T const_cast(T)(const T obj) { return to!(T)(obj); } But i think that there must exist a more nicer way to cast away const, isn't there? To cast away "const" with a simple cast to "T" fails (see my post above), because i have no idea, how i can restrict my opCast. So i have to convert it again with "to". Do some of you have any ideas how i can restrict my opCast, so my const_cast doesn't match it, e.g. with some template magic?
May 03 2012
next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, May 03, 2012 09:33:01 Namespace wrote:
 On Wednesday, 2 May 2012 at 22:38:36 UTC, Namespace wrote:
 Other, shorter example:
 
 [code]
 import std.stdio, std.traits;
 
 class A {
 
 	int val;
 	
 	alias val this;
 	
 	T opCast(T : Object)() {
 	
 		writeln("FOO");
 		
 		return to!(T)(this);
 	
 	}
 
 }
 
 class B : A {
 
 }
 
 T to(T : Object, U : Object)(const U obj) {
 
 	return *(cast(T*) &obj);
 
 }
 
 T const_cast(T)(const T obj) {
 
 	return cast(T) obj;
 
 }
 
 void main () {
 
 	A a = new B();
 	a.val = 42;
 	
 	writefln("a.val: %d", a.val);
 	
 	B* b = cast(B*) &a;
 	writefln("*b.val: %d", b.val);
 	
 	B b1 = to!(B)(a);
 	writefln("b1.val: %d", b1.val);
 	
 	B b2 = cast(B) a;
 	writefln("b2.val: %d", b2.val);
 	
 	const B b3 = cast(B) a;
 	
 	B b4 = const_cast(b3);
 
 }
 [/code]
 
 print:
 
 alias_this_impl.d(24): Error: function
 alias_this_impl.A.opCast!(B).opCast () is
 
  not callable using argument types ()
 
 alias_this_impl.d(44): Error: template instance
 alias_this_impl.const_cast!(B) e
 rror instantiating
 
 I'm not very skillful in such "template" stories. Maybe someone
 can help me?
Solved with T const_cast(T)(const T obj) { return to!(T)(obj); } But i think that there must exist a more nicer way to cast away const, isn't there? To cast away "const" with a simple cast to "T" fails (see my post above), because i have no idea, how i can restrict my opCast. So i have to convert it again with "to". Do some of you have any ideas how i can restrict my opCast, so my const_cast doesn't match it, e.g. with some template magic?
If you want to restrict opCast, then use a template constraint, constraining it to what you want to work with it. Also, casting away const is generally a bad idea in D. Casting away const and mutating a variable is an _extremely_ bad idea. You _really_ shouldn't be doing it. So, the fact that you _have_ a function which is specifically trying to cast away const is almost certainly _not_ a good idea. http://stackoverflow.com/questions/4219600/logical-const-in-d - Jonathan M Davis
May 03 2012
parent reply "Namespace" <rswhite4 googlemail.com> writes:
 If you want to restrict opCast, then use a template constraint, 
 constraining
 it to what you want to work with it. Also, casting away const 
 is generally a
 bad idea in D. Casting away const and mutating a variable is an 
 _extremely_
 bad idea. You _really_ shouldn't be doing it. So, the fact that 
 you _have_ a
 function which is specifically trying to cast away const is 
 almost certainly
 _not_ a good idea.

 http://stackoverflow.com/questions/4219600/logical-const-in-d


 - Jonathan M Davis
So, you mean that if i declared any parameter as const, it have to stay const all the time? What would you do, if you need in a special case a mutable version or must change the object itself? Because there is no "mutable" keyword in D you have to cast away the constness.
May 03 2012
parent reply "Chris Cain" <clcain uncg.edu> writes:
On Thursday, 3 May 2012 at 08:00:43 UTC, Namespace wrote:
 So, you mean that if i declared any parameter as const, it have 
 to stay const all the time?
Yes. const = you can't change. Changing it is invalid behavior. Imagine const/immutable as bits in readonly memory and you'll have to right mindset.
 What would you do, if you need in a special case a mutable 
 version or must change the object itself?
 Because there is no "mutable" keyword in D you have to cast 
 away the constness.
In what way do you mean? If it's something you honestly _need_ to change and it's const, then maybe throwing an exception would be appropriate.
May 03 2012
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 3 May 2012 at 08:46:26 UTC, Chris Cain wrote:
 On Thursday, 3 May 2012 at 08:00:43 UTC, Namespace wrote:
 So, you mean that if i declared any parameter as const, it 
 have to stay const all the time?
Yes. const = you can't change. Changing it is invalid behavior. Imagine const/immutable as bits in readonly memory and you'll have to right mindset.
 What would you do, if you need in a special case a mutable 
 version or must change the object itself?
 Because there is no "mutable" keyword in D you have to cast 
 away the constness.
In what way do you mean? If it's something you honestly _need_ to change and it's const, then maybe throwing an exception would be appropriate.
I thought that const = "cannot change directly" and immutable stands for "cannot change all the time". If not, why exist both storage classes beside?
May 03 2012
next sibling parent reply "Chris Cain" <clcain uncg.edu> writes:
On Thursday, 3 May 2012 at 08:54:48 UTC, Namespace wrote:
 I thought that const = "cannot change directly" and immutable 
 stands for "cannot change all the time". If not, why exist both 
 storage classes beside?
const = you (as in, your view of the data as you're working with it) can't change immutable = no one can change it ... as in, there exists no view of the data that can mutate it. It's a subtle distinction. In fact, you can be handed a "const" and it's actually immutable underneath. And since immutable data can actually be stored in read only memory...
May 03 2012
parent "Chris Cain" <clcain uncg.edu> writes:
On Thursday, 3 May 2012 at 09:00:08 UTC, Chris Cain wrote:
 const = you (as in, your view of the data as you're working 
 with it) can't change
Actually, let me be even clearer with this... I mean _you_ cannot change it, but it might be changed by someone else's view, in which case it would appear to change in your view ... but not by any interaction you make with it. This means concretely that anything you do with the object will have no effect on its bit representation in memory, although the bit representation in memory might be changed by other threads/processes/views.
May 03 2012
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, May 03, 2012 10:54:47 Namespace wrote:
 On Thursday, 3 May 2012 at 08:46:26 UTC, Chris Cain wrote:
 On Thursday, 3 May 2012 at 08:00:43 UTC, Namespace wrote:
 So, you mean that if i declared any parameter as const, it
 have to stay const all the time?
Yes. const = you can't change. Changing it is invalid behavior. Imagine const/immutable as bits in readonly memory and you'll have to right mindset.
 What would you do, if you need in a special case a mutable
 version or must change the object itself?
 Because there is no "mutable" keyword in D you have to cast
 away the constness.
In what way do you mean? If it's something you honestly _need_ to change and it's const, then maybe throwing an exception would be appropriate.
I thought that const = "cannot change directly" and immutable stands for "cannot change all the time". If not, why exist both storage classes beside?
An immutable variable can never be changed by any reference to that data. It's also implicitly shared across threads (since it can never change). If a const variable is a value type, then there really isn't any difference between const and immutable. If it's a reference type, then it just indicates that that particular reference cannot alter the data. Another reference may or may not be able to (and const is _not_ implicitly shared across threads, because the data _can_ change if there are mutable references to it). But if a reference is const, it's breaking the type system to cast away const and alter the data precisely because the compiler can't know whether that data is actually mutable or not. For instance, what if if you did something like const var = new immutable(A); var may be const, but it refers to a value which is actually immutable. Depending on what the compiler does, mutating var could result in nasty stuff like segfaults. In the general case, the compiler has no way of knowing whether a const variable is really mutable or immutable underneath. So, casting away const and mutating a variable is undefined behavior. As far as the compiler is concerned, a variable is _never_ mutated through a const reference, and it will optimize code based on that. So, casting away const can not only result in segfaults if the data is actually immutable, but it can result in incorrect behavior due to optimizations that the compiler makes based on the assumption that the variable wouldn't change but which you violated by casting away const and mutating the variable. Unlike immutable, _other_ references to the data may mutate it (and the compiler must take that into account when optimizing), but you should never try and mutate a const variable. Once something is const, _leave_ it that way. If you need a mutable reference to it, then you need to get one which was mutable in the first place rather than coming from the const reference through casting. Casting away const is legal, because D is a systems language, but actually mutating the variable after casting away const is undefined behavior, so you should never do it unless you really know what you're doing. http://stackoverflow.com/questions/4219600/logical-const-in-d - Jonathan M Davis
May 03 2012
prev sibling parent sclytrack <sclytrack ars.com> writes:
On 05/03/2012 09:33 AM, Namespace wrote:
 On Wednesday, 2 May 2012 at 22:38:36 UTC, Namespace wrote:
 Other, shorter example:

 [code]
 import std.stdio, std.traits;

 class A {
 int val;

 alias val this;

 T opCast(T : Object)() {
 writeln("FOO");

 return to!(T)(this);
 }
 }

 class B : A {

 }

 T to(T : Object, U : Object)(const U obj) {
 return *(cast(T*) &obj);
 }

 T const_cast(T)(const T obj) {
 return cast(T) obj;
 }

 void main () {
 A a = new B();
 a.val = 42;

 writefln("a.val: %d", a.val);

 B* b = cast(B*) &a;
 writefln("*b.val: %d", b.val);

 B b1 = to!(B)(a);
 writefln("b1.val: %d", b1.val);

 B b2 = cast(B) a;
 writefln("b2.val: %d", b2.val);

 const B b3 = cast(B) a;

 B b4 = const_cast(b3);
 }
 [/code]

 print:

 alias_this_impl.d(24): Error: function
 alias_this_impl.A.opCast!(B).opCast () is
 not callable using argument types ()
 alias_this_impl.d(44): Error: template instance
 alias_this_impl.const_cast!(B) e
 rror instantiating

 I'm not very skillful in such "template" stories. Maybe someone can
 help me?
Solved with T const_cast(T)(const T obj) { return to!(T)(obj); } But i think that there must exist a more nicer way to cast away const, isn't there? To cast away "const" with a simple cast to "T" fails (see my post above), because i have no idea, how i can restrict my opCast. So i have to convert it again with "to". Do some of you have any ideas how i can restrict my opCast, so my const_cast doesn't match it, e.g. with some template magic?
Unqual können Sie finden in std.traits. template Unqual(T) { version (none) // Error: recursive alias declaration BUG1308 { static if (is(T U == const U)) alias Unqual!U Unqual; else static if (is(T U == immutable U)) alias Unqual!U Unqual; else static if (is(T U == inout U)) alias Unqual!U Unqual; else static if (is(T U == shared U)) alias Unqual!U Unqual; else alias T Unqual; } else // workaround { static if (is(T U == shared(const U))) alias U Unqual; else static if (is(T U == const U )) alias U Unqual; else static if (is(T U == immutable U )) alias U Unqual; else static if (is(T U == inout U )) alias U Unqual; else static if (is(T U == shared U )) alias U Unqual; else alias T Unqual; } } unittest { static assert(is(Unqual!(int) == int)); static assert(is(Unqual!(const int) == int)); static assert(is(Unqual!(immutable int) == int)); static assert(is(Unqual!(inout int) == int)); static assert(is(Unqual!(shared int) == int)); static assert(is(Unqual!(shared(const int)) == int)); alias immutable(int[]) ImmIntArr; static assert(is(Unqual!(ImmIntArr) == immutable(int)[])); }
May 03 2012
prev sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Thu, 03 May 2012 00:38:35 +0200, Namespace <rswhite4 googlemail.com>  
wrote:

 I'm not very skillful in such "template" stories. Maybe someone can help  
 me?
The main problem here is your opCast is non-const. (it's always an indication of const problems when DMD says "<X> is not callable using argument types ()") Solution: class A { int val; alias val this; T opCast(T : Object)() { writeln("FOO"); return to!(T)(this); } // Add this T opCast(T : Object)() const { writeln("FOO"); return to!(T)(this); } }
May 03 2012
next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 3 May 2012 at 07:41:32 UTC, Simen Kjaeraas wrote:
 On Thu, 03 May 2012 00:38:35 +0200, Namespace 
 <rswhite4 googlemail.com> wrote:

 I'm not very skillful in such "template" stories. Maybe 
 someone can help me?
The main problem here is your opCast is non-const. (it's always an indication of const problems when DMD says "<X> is not callable using argument types ()") Solution: class A { int val; alias val this; T opCast(T : Object)() { writeln("FOO"); return to!(T)(this); } // Add this T opCast(T : Object)() const { writeln("FOO"); return to!(T)(this); } }
Hm, simple. Thank you, as long as the bug isn't fixed, this has to be enough. :)
May 03 2012
prev sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 3 May 2012 at 07:41:32 UTC, Simen Kjaeraas wrote:
 On Thu, 03 May 2012 00:38:35 +0200, Namespace 
 <rswhite4 googlemail.com> wrote:

 I'm not very skillful in such "template" stories. Maybe 
 someone can help me?
The main problem here is your opCast is non-const. (it's always an indication of const problems when DMD says "<X> is not callable using argument types ()") Solution: class A { int val; alias val this; T opCast(T : Object)() { writeln("FOO"); return to!(T)(this); } // Add this T opCast(T : Object)() const { writeln("FOO"); return to!(T)(this); } }
My tests are failed, but isn't it possible, to reduce both methods to one with the inout keyword?
May 03 2012