Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Real world application of widening / narrowing conversion?

Tags:

java

c++

casting

Can someone please explain why you would ever use widening or narrowing conversion? I've read a lot about these but no one ever gives me a practical example. Thanks!

like image 591
Hermes Trismegistus Avatar asked May 27 '13 23:05

Hermes Trismegistus


2 Answers

(Java) Widening and Narrowing Conversions have to do with converting between related Types. Take, for example, the relationship between an abstract (super) class and its (child) subclass; let's use the java.lang.Number Class (abstract) and a direct subclass Integer. Here we have:

(superclass)                               Number
                                   __________/\__________
                                  /       |      |       \
(concrete subclasses)          Integer   Long    Float   Double

Widening Conversion: occurs if we take a specific type (subclass) and attempt to assign it to a less specific type (superclass).

Integer i = new Integer(8);
Number n = i;   // this is widening conversion; no need to cast

Narrowing Conversion: occurs when we take a less specific type (superclass) and attempt to assign it to a more specific type (subclass), which requires explicit casting.

Number n = new Integer(5); // again, widening conversion
Integer i = (Integer) n;   // narrowing; here we explicitly cast down to the type we want - in this case an Integer

There are certain issues that you need to be aware of such as ClassCastExceptions:

Integer i = new Integer(5);
Double d = new Double(13.3);
Number n;

 n = i; // widening conversion - OK
 n = d; // also widening conversion - OK

 i = (Integer) d;  // cannot cast from Double to Integer - ERROR

 // remember, current n = d (a Double type value)
 i = (Integer) n;  // narrowing conversion; appears OK, but will throw ClassCastException at runtime - ERROR

One way to handle this is to use an if statement with the instanceof keyword:

 if( n instanceof Integer) {
      i = (Integer) n;
 }

Why would you want to use this? Let's say you are making a hierarchy of personnel for some program and you have a generic superclass called "Person" which takes a first and last name as parameters, and subclasses "Student", "Teacher", "Secretary", etc.. Here you can initially create a generic person, and assign it (through inheritance) to, say, a Student which would have an additional variable field for studenID set in it's constructor. You can use a single method that takes the more generic (wider) type as a parameter and handle all subclasses of that type as well:

 public static void main(String[] args) {
     Person p = new Student("John", "Smith", 12345);
     printInfo(p);
 }

 // this method takes the wider Person type as a parameter, though we can send it a narrower type such as Student if we want
 public static void printInfo(Person p) {
     System.out.println("First: " + p.getFirstName());
     System.out.println("Last: " + p.getLastName());
     if (p instanceof Student) {
         System.out.println( (Student)p).getStudentID() );  // we cast p to Student with Narrow Conversion which allows us to call the getStudentID() method; only after ensuring the p is an instance of Student
     }
}

I realize this may not be the ideal way to handle things, but for the sake of demonstration I thought it served to show some of the possibilities.

like image 178
Brandon K Avatar answered Oct 05 '22 22:10

Brandon K


If some code returns an int containing a true/false value, you could shorten it yourself to a bool which is what it properly represents.
You can also do the opposite.

You can widen a char to int to do some comparisons with ascii values.

You can take an instance of Dog and widen it to IAnimal to pass it to a function.

You can shorten a IAnimal to Dog when you know the type of animal in a List<IAnimal> in a factory or elsewhere for whatever reason.

like image 23
Jean-Bernard Pellerin Avatar answered Oct 05 '22 22:10

Jean-Bernard Pellerin