Implicit conversion design issues

G

Girish

Im trying to understand implicit type conversions from object -> string and
vice versa.

I have two classes, one Driver and one called StringWrapper. These are just
test classes that try and emulate the pattern im trying to follow in an
existing project.

These are my steps:
1) I have a method "printMe" existing in the application which originally
used to take in a string. This method is static and sits in the Driver
class. I cannot remove this method since it public and is used all over the
application.
2) Now, Ive realised that I need to do some parsing and cleaning up of the
string before the method can continue to execute its logic (printMe).
3) My solution was to change the method sig to take in a StringWrapper
class, created by me, that will take in an implicit string and return a
StringWrapper object with the cleaned up string.
4) Now, when the StringWapper object is used by the code in the method
printMe, I want to treat it as a String object and not a StringWrapper
object. So what Ive done is create another implicit conversion from
StringWrapper to String.

I hope this makes sense at this point. Essentially Im tring to minimize code
changes in the code that calls my printMe method so that it knows of only
String objects. AND the reminaing logic in printMe function should only know
of String objects as well. So the StringWrapper class will essentially
convert string to an object of its type, do the cleaning of the string and
then, whereever the StringWrapper instance is used in printMe method, it
should expose itself as a String instead.

So my question is
1) In my printMe method, I had a statement called
Console.Write(val.ToLower()). This threw me an exception because it said the
StringWrapper does not support the ToLower method. How come even though I
have an implicit conversion?
2) If I do Console.Write(((string)val).ToLower()); it works!! Even though
this is an explicit conversion and I havent defined any explicit
conversions....

Im kinda lost here.... can anyone help me with a solution to this problem?

Thanks,
Girish

Driver Class
-------------
using System;
namespace test1 {
class Driver {
//old func sig was; static public void printMe(String val)
static public void printMe(StringWrapper val) {
//Console.Write(val.ToLower()); //old
Console.Write(((string)val).ToLower());
}

[STAThread]
static void Main(string[] args) {
String b = "Testing 123";
Driver.printMe(b);

//wait for input before exiting
Console.Read();
}
}
}


StringWrapper Class
---------------------
using System;
namespace test1 {
public class StringWrapper {
private String _val;

public String val {
get { return _val; }
}

public StringWrapper(String val) {
this._val = val;
}

static public implicit operator StringWrapper(String val) {
val += " (im changed)";
return new StringWrapper(val);
}

static public implicit operator string(StringWrapper val) {
return val.val;
}
}
}
 
G

Girish

For those of you who thought I didnt attach any code, since ive wrote a long
email, you can find the code at the bottom of my earlier post. I know some
people must be going... OK im reading all this stuff.. so wheres the code
now???

:):):):)


Girish said:
Im trying to understand implicit type conversions from object -> string
and vice versa.

I have two classes, one Driver and one called StringWrapper. These are
just test classes that try and emulate the pattern im trying to follow in
an existing project.

These are my steps:
1) I have a method "printMe" existing in the application which originally
used to take in a string. This method is static and sits in the Driver
class. I cannot remove this method since it public and is used all over
the application.
2) Now, Ive realised that I need to do some parsing and cleaning up of the
string before the method can continue to execute its logic (printMe).
3) My solution was to change the method sig to take in a StringWrapper
class, created by me, that will take in an implicit string and return a
StringWrapper object with the cleaned up string.
4) Now, when the StringWapper object is used by the code in the method
printMe, I want to treat it as a String object and not a StringWrapper
object. So what Ive done is create another implicit conversion from
StringWrapper to String.

I hope this makes sense at this point. Essentially Im tring to minimize
code changes in the code that calls my printMe method so that it knows of
only String objects. AND the reminaing logic in printMe function should
only know of String objects as well. So the StringWrapper class will
essentially convert string to an object of its type, do the cleaning of
the string and then, whereever the StringWrapper instance is used in
printMe method, it should expose itself as a String instead.

So my question is
1) In my printMe method, I had a statement called
Console.Write(val.ToLower()). This threw me an exception because it said
the StringWrapper does not support the ToLower method. How come even
though I have an implicit conversion?
2) If I do Console.Write(((string)val).ToLower()); it works!! Even though
this is an explicit conversion and I havent defined any explicit
conversions....

Im kinda lost here.... can anyone help me with a solution to this problem?

Thanks,
Girish

Driver Class
-------------
using System;
namespace test1 {
class Driver {
//old func sig was; static public void printMe(String val)
static public void printMe(StringWrapper val) {
//Console.Write(val.ToLower()); //old
Console.Write(((string)val).ToLower());
}

[STAThread]
static void Main(string[] args) {
String b = "Testing 123";
Driver.printMe(b);

//wait for input before exiting
Console.Read();
}
}
}


StringWrapper Class
---------------------
using System;
namespace test1 {
public class StringWrapper {
private String _val;

public String val {
get { return _val; }
}

public StringWrapper(String val) {
this._val = val;
}

static public implicit operator StringWrapper(String val) {
val += " (im changed)";
return new StringWrapper(val);
}

static public implicit operator string(StringWrapper val) {
return val.val;
}
}
}
 
V

VJ

Oh ... Ok maybe this seems simple to me.. but I might miss something
application specfic.. if you are able to change the signature.. I assume you
have the source code.. why can't you write the cleanup code as the first few
lines of the printMe and make it simple?

VJ

Girish said:
For those of you who thought I didnt attach any code, since ive wrote a
long email, you can find the code at the bottom of my earlier post. I know
some people must be going... OK im reading all this stuff.. so wheres the
code now???

:):):):)


Girish said:
Im trying to understand implicit type conversions from object -> string
and vice versa.

I have two classes, one Driver and one called StringWrapper. These are
just test classes that try and emulate the pattern im trying to follow in
an existing project.

These are my steps:
1) I have a method "printMe" existing in the application which originally
used to take in a string. This method is static and sits in the Driver
class. I cannot remove this method since it public and is used all over
the application.
2) Now, Ive realised that I need to do some parsing and cleaning up of
the string before the method can continue to execute its logic (printMe).
3) My solution was to change the method sig to take in a StringWrapper
class, created by me, that will take in an implicit string and return a
StringWrapper object with the cleaned up string.
4) Now, when the StringWapper object is used by the code in the method
printMe, I want to treat it as a String object and not a StringWrapper
object. So what Ive done is create another implicit conversion from
StringWrapper to String.

I hope this makes sense at this point. Essentially Im tring to minimize
code changes in the code that calls my printMe method so that it knows of
only String objects. AND the reminaing logic in printMe function should
only know of String objects as well. So the StringWrapper class will
essentially convert string to an object of its type, do the cleaning of
the string and then, whereever the StringWrapper instance is used in
printMe method, it should expose itself as a String instead.

So my question is
1) In my printMe method, I had a statement called
Console.Write(val.ToLower()). This threw me an exception because it said
the StringWrapper does not support the ToLower method. How come even
though I have an implicit conversion?
2) If I do Console.Write(((string)val).ToLower()); it works!! Even though
this is an explicit conversion and I havent defined any explicit
conversions....

Im kinda lost here.... can anyone help me with a solution to this
problem?

Thanks,
Girish

Driver Class
-------------
using System;
namespace test1 {
class Driver {
//old func sig was; static public void printMe(String val)
static public void printMe(StringWrapper val) {
//Console.Write(val.ToLower()); //old
Console.Write(((string)val).ToLower());
}

[STAThread]
static void Main(string[] args) {
String b = "Testing 123";
Driver.printMe(b);

//wait for input before exiting
Console.Read();
}
}
}


StringWrapper Class
---------------------
using System;
namespace test1 {
public class StringWrapper {
private String _val;

public String val {
get { return _val; }
}

public StringWrapper(String val) {
this._val = val;
}

static public implicit operator StringWrapper(String val) {
val += " (im changed)";
return new StringWrapper(val);
}

static public implicit operator string(StringWrapper val) {
return val.val;
}
}
}
 
G

Girish

True, I could have. But for the future, I can just let everyone know, use
the StringWrapper class from now on people for your string manuplilation.
This is easier than telling everyone, hey when you write a method in the
future, remember to call this other helper function and make sure its called
before any other code.

I dont know, but i usually like to have more than one way of doing things
and pick whats appropriate.... and if the implicit cast mehod is not the way
to go... id really appreciate it if someone can help me understand why. :)

thanks!
Girish

VJ said:
Oh ... Ok maybe this seems simple to me.. but I might miss something
application specfic.. if you are able to change the signature.. I assume
you have the source code.. why can't you write the cleanup code as the
first few lines of the printMe and make it simple?

VJ

Girish said:
For those of you who thought I didnt attach any code, since ive wrote a
long email, you can find the code at the bottom of my earlier post. I
know some people must be going... OK im reading all this stuff.. so
wheres the code now???

:):):):)


Girish said:
Im trying to understand implicit type conversions from object -> string
and vice versa.

I have two classes, one Driver and one called StringWrapper. These are
just test classes that try and emulate the pattern im trying to follow
in an existing project.

These are my steps:
1) I have a method "printMe" existing in the application which
originally used to take in a string. This method is static and sits in
the Driver class. I cannot remove this method since it public and is
used all over the application.
2) Now, Ive realised that I need to do some parsing and cleaning up of
the string before the method can continue to execute its logic
(printMe).
3) My solution was to change the method sig to take in a StringWrapper
class, created by me, that will take in an implicit string and return a
StringWrapper object with the cleaned up string.
4) Now, when the StringWapper object is used by the code in the method
printMe, I want to treat it as a String object and not a StringWrapper
object. So what Ive done is create another implicit conversion from
StringWrapper to String.

I hope this makes sense at this point. Essentially Im tring to minimize
code changes in the code that calls my printMe method so that it knows
of only String objects. AND the reminaing logic in printMe function
should only know of String objects as well. So the StringWrapper class
will essentially convert string to an object of its type, do the
cleaning of the string and then, whereever the StringWrapper instance is
used in printMe method, it should expose itself as a String instead.

So my question is
1) In my printMe method, I had a statement called
Console.Write(val.ToLower()). This threw me an exception because it said
the StringWrapper does not support the ToLower method. How come even
though I have an implicit conversion?
2) If I do Console.Write(((string)val).ToLower()); it works!! Even
though this is an explicit conversion and I havent defined any explicit
conversions....

Im kinda lost here.... can anyone help me with a solution to this
problem?

Thanks,
Girish

Driver Class
-------------
using System;
namespace test1 {
class Driver {
//old func sig was; static public void printMe(String val)
static public void printMe(StringWrapper val) {
//Console.Write(val.ToLower()); //old
Console.Write(((string)val).ToLower());
}

[STAThread]
static void Main(string[] args) {
String b = "Testing 123";
Driver.printMe(b);

//wait for input before exiting
Console.Read();
}
}
}


StringWrapper Class
---------------------
using System;
namespace test1 {
public class StringWrapper {
private String _val;

public String val {
get { return _val; }
}

public StringWrapper(String val) {
this._val = val;
}

static public implicit operator StringWrapper(String val) {
val += " (im changed)";
return new StringWrapper(val);
}

static public implicit operator string(StringWrapper val) {
return val.val;
}
}
}
 
D

Daniel O'Connell [C# MVP]

So my question is
1) In my printMe method, I had a statement called
Console.Write(val.ToLower()). This threw me an exception because it said
the StringWrapper does not support the ToLower method. How come even
though I have an implicit conversion?

Implicit conversions are only applied in some circumstances, method
resolution is not one of them(atleast while resolving the method set the
type has. Conversions for parameters are considered while dealing with
overload resolution, but the type of the variable is static.) As far as the
compiler is concerned, the only methods your type has are those it or its
bases define.
2) If I do Console.Write(((string)val).ToLower()); it works!! Even though
this is an explicit conversion and I havent defined any explicit
conversions....

By casting here you are telling the compiler you want to cause the
conversion. Since implicit conversions do not happen during method
resolution, you have to explicitly tell the compiler to perform the
conversion and to call string::ToLower().
 
G

Girish

Thanks for your reply Daniel. I have more qs, and maybe these are silly qs
but please bear with me.

1) Why does the compiler not complain that I dont have an explicit cast
specified in my type? I know you cannot have both implicit and explicit
defined but if im stating I need to envoke an explicit cast - it somehow
"understands" i really mean execute the implicit cast method.. If the answer
to this q is "well, thats the way it is...", i guess I can live with that.
:)

2) Do conversions of types only happen during overloading? What are the
other circumstances?

3) I noticed that this pattern causes an infinite loop. Shouldnt the
complier choke at this?

static public implicit operator StringWrapper(String val) {
val += " (im changed)";
//return new StringWrapper(val);
return val;
}

g
 
B

Brant Estes

I guess the first step is understanding what implicit and explicit
operators are. What they effectively do, is convert one type to
another. The difference between implicit and explicit operators, is
whether or not you need to cast or not.

Consider your own code, and assume for now you didn't implement the
implicit operator:

StringWrapper sw = new StringWrapper("some value");
string s = sw; // this will fail if you don't have an implicit operator
string s = (string)sw; // this fail if you don't have an explicit
operator.
One thing I've noticed developers have to understand, is that
converting from one type to another, doesn't just happen magically,
code needs to exist, which in this case, is the implicit and explicit
operators.

It looks like what you're trying to do, is build additional
functionality into the string class. You probably tried what many of
us already did, and do:

public class StringWrapper : System.String {}

You probably also realized, that this is impossible, because
System.String is a sealed class (along with most of the other primitive
types you'd like to extend from time to time), so this prevents you
from inheriting from it.

Your best bet, would be to keep your implicit operators in place, to
ease development. But in your example:

static public void printMe(StringWrapper val) {
//Console.Write(val.ToLower())­; //old
Console.Write(((string)val).To­Lower());
}

The parameter "val" is of type StringWrapper, and not string. You can
easily convert between the two using your implicit operators, but that
doesn't mean their methods are inherited from each other.

In order to use the ToLower() method, you will need to get a variable
of type string, because it's the string class which has that method
defined, not your StringWrapper.

Since you have your implicit operator defined, this a pretty simple
process:

static public void printMe(StringWrapper val) {
//Console.Write(val.ToLower())­; //old
string newVal = val;
Console.Write(newVal.To­Lower());
}

I hope this clarifies what your understanding of implicit conversions,
and how they're used.

Brant Estes
 
D

Daniel O'Connell [C# MVP]

Girish said:
Thanks for your reply Daniel. I have more qs, and maybe these are silly qs
but please bear with me.

Its no problem. Conversions and overloading are the most confusing parts of
the spec, atleast from a compiler writer's point of view. I don't mind
trying to explain it.
1) Why does the compiler not complain that I dont have an explicit cast
specified in my type? I know you cannot have both implicit and explicit
defined but if im stating I need to envoke an explicit cast - it somehow
"understands" i really mean execute the implicit cast method.. If the
answer to this q is "well, thats the way it is...", i guess I can live
with that. :)

Well, "thats the way it is" is pretty close to it, but its not complete, ;).
Basically the rules are an explicit cconversion must be explicitly
declared(using a cast operator), while an implicit cast may or may not be
explicit. In my opinion this is done to allow for exactly what you are
seeing here, that is permit the coder to explicitly tell the compiler to
perform a conversion in a situation where implicit conversions are not in
effect.
2) Do conversions of types only happen during overloading? What are the
other circumstances?

Implicit conversions are possible during any assignment, return or parameter
pass operation(both of which you could consider an assignment and look like
or are assignments in other languages). Overload resolution takes
conversions in account to determine the proper overload, assignment takes it
in account to determine if any conversion steps are required between the
source and the target type, casting can obviously explicitly cause a
conversion, a return statement can cause .

I don't think there are any other circumstances where this happens, but I
don't have the spec on hand to be sure(can't recall off hand if implicit
conversions to bool are considered in if statements, for example).
3) I noticed that this pattern causes an infinite loop. Shouldnt the
complier choke at this?

static public implicit operator StringWrapper(String val) {
val += " (im changed)";
//return new StringWrapper(val);
return val;
}

The compiler should probably spit out a warning that you are going to enter
an infinite loop, but it *is* legal code. The reason for this is that the
compiler cannot really tell that the infinite recursion is going to happen,
just that its likely or possible. While its obvious to us, without being
able to understand the method as a whole, the compiler could only guess as
to if you actually meant to cause recursion or not. Thus it is something it
should probably warn about, but not emit an error.
 
G

Girish

Thanks for your reply Brant. It helped. Indeed, your right. I did try and
start this out by extending the String class - but I noticed that the String
class was sealed in the docs... then I started to think of a way to do what
I need to do with *minimum* impact to the calling code and the executing
code. Then i remembered that String objects can be created without having to
do a "new". And then it struck me there has to be a way I can create an
string and assign it to my own type without a "new". Passing objects into
method parameters seemed like writing stringwrapper a = "xyz" to me and
thats where all this started from. At that time I didnt know this concept is
called operator overloading. But now I know. :)

Girish


I guess the first step is understanding what implicit and explicit
operators are. What they effectively do, is convert one type to
another. The difference between implicit and explicit operators, is
whether or not you need to cast or not.

Consider your own code, and assume for now you didn't implement the
implicit operator:

StringWrapper sw = new StringWrapper("some value");
string s = sw; // this will fail if you don't have an implicit operator
string s = (string)sw; // this fail if you don't have an explicit
operator.
One thing I've noticed developers have to understand, is that
converting from one type to another, doesn't just happen magically,
code needs to exist, which in this case, is the implicit and explicit
operators.

It looks like what you're trying to do, is build additional
functionality into the string class. You probably tried what many of
us already did, and do:

public class StringWrapper : System.String {}

You probably also realized, that this is impossible, because
System.String is a sealed class (along with most of the other primitive
types you'd like to extend from time to time), so this prevents you
from inheriting from it.

Your best bet, would be to keep your implicit operators in place, to
ease development. But in your example:

static public void printMe(StringWrapper val) {
//Console.Write(val.ToLower())­; //old
Console.Write(((string)val).To­Lower());
}

The parameter "val" is of type StringWrapper, and not string. You can
easily convert between the two using your implicit operators, but that
doesn't mean their methods are inherited from each other.

In order to use the ToLower() method, you will need to get a variable
of type string, because it's the string class which has that method
defined, not your StringWrapper.

Since you have your implicit operator defined, this a pretty simple
process:

static public void printMe(StringWrapper val) {
//Console.Write(val.ToLower())­; //old
string newVal = val;
Console.Write(newVal.To­Lower());
}

I hope this clarifies what your understanding of implicit conversions,
and how they're used.

Brant Estes
 
G

Girish

Thansk for helping me out Daniel. I bet if you had a buck for every thank
you expressed by a person you helped, Im sure youd be real rich!!!! if your
not already tho.. ;-)

Thanks a million for what its worth. :)

girish
 

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

Top