/* types2.c
 *
 * So here is an workaround: define a new type,
 * which can be either an integer or a float, which has
 * within it a "tag" that indicates what type of data it is.
 *
 * (In this implementation, each intfloat needs space for
 *  three things: the type, the possible int value, and 
 *  the possible float value. Better would be using a C union
 *  to have the latter two occupy the same memory.)
 *
 *     $ gcc types2.c -o types2        # compile C program
 *     $ ./types2                      # run it
 *     -- int float -- 
 *     3 + 4 is 7 
 *     -- int plus -- 
 *     3.2 + 4.1 is 7.3 
 *
 * Jim Mahoney | cs.bennington.college | MIT License | Oct 2021
 */

#define _INT_   1
#define _FLOAT_ 2

#include <stdio.h>

typedef struct _intfloat intfloat;   // define a new "intfloat" type
struct _intfloat {                   // ... with these internals.
  int type;      // "tagged" data, i.e. _INT_ or _FLOAT_
  int i;         // integer value
  float f;       // float value
};
  
intfloat plus(intfloat a, intfloat b){
  // add two integer-or-float things to get a new integer-or-float thing
  intfloat result;
  switch(a.type){
  case _INT_:
    printf(" -- int float -- \n");
    result.type = _INT_;
    result.i = a.i + b.i;
    break;
  case _FLOAT_:
    printf(" -- int plus -- \n");
    result.type = _FLOAT_;
    result.f = a.f + b.f;
    break;
  }
  return result;
}

intfloat intfloat_from_int(int a){
  intfloat result;
  result.type = _INT_;
  result.i = a;
  return result;
}

intfloat intfloat_from_float(float a){
  intfloat result;
  result.type = _FLOAT_;
  result.f = a;
  return result;
}

int main(){
  intfloat i, j, x, y, result;

  i = intfloat_from_int(3);  // fill two integer intfloats
  j = intfloat_from_int(4);

  x = intfloat_from_float(3.2);  // fill two float intfloats
  y = intfloat_from_float(4.1);

  result = plus(i ,j);  // add two integers
  printf(" %d + %d is %d \n", i.i, j.i, result.i);  

  result = plus(x ,y);  // add two floats
  printf(" %g + %g is %g \n", x.f, y.f, result.f);
  
  return 0;
}