Index: libcfa/prelude/builtins.c
===================================================================
--- libcfa/prelude/builtins.c	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ libcfa/prelude/builtins.c	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -178,4 +178,10 @@
 } // distribution
 
+struct quasi_void {};
+static inline void ?{}(quasi_void &) {}
+static inline void ?{}(quasi_void &, quasi_void) {}
+static inline void ^?{}(quasi_void &) {}
+static inline quasi_void ?=?(quasi_void &, quasi_void & _src) { return _src; }
+
 // Local Variables: //
 // mode: c //
Index: libcfa/src/enum.cfa
===================================================================
--- libcfa/src/enum.cfa	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ libcfa/src/enum.cfa	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -1,16 +1,14 @@
 #include "enum.hfa"
+#include "fstream.hfa"
 
 #pragma GCC visibility push(default)
 
-forall(T, E| TypedEnum(T, E)) {
-    // constructors
+forall(ostype & | basic_ostream(ostype), E, V| CfaEnum(E, V))
+ostype & ?|?(ostype& os, E e) {
+    return os | type_name(e) | "." | labelE(e);
+}
 
-    // comparison
-    int ?==?(E l, E r) { return posE(l) == posE(r); }
-    int ?!=?(E l, E r) { return posE(l) != posE(r); }
-    int ?!=?(E l, zero_t) { return !( posE(l) == 0 ); }
-    int ?<?(E l, E r) { return posE(l) < posE(r); }
-    int ?<=?(E l, E r) { return posE(l) <= posE(r); }
-    int ?>?(E l, E r) { return posE(l) > posE(r); }
-    int ?>=?(E l, E r) {  return posE(l) >= posE(r); }
+forall(ostype & | basic_ostream(ostype), E| CfaEnum(E, quasi_void))
+ostype & ?|?(ostype& os, E e) {
+    return os | type_name(e) | "." | labelE(e);
 }
Index: libcfa/src/enum.hfa
===================================================================
--- libcfa/src/enum.hfa	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ libcfa/src/enum.hfa	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -1,36 +1,39 @@
 #pragma once
 
-forall(T) { // T is the based type of enum(T)
-    forall(E) trait Bounded {
-        E lowerBound();
-        E upperBound();
-    };
+#include "iostream.hfa"
 
-    forall(E| Bounded(T, E)) trait Serial {
-        unsigned fromInstance(E e);
-        E fromInt(unsigned i);
-        E succ(E e);
-        E pred(E e);
-    };
+forall(E) trait Bounded {
+    E lowerBound();
+    E upperBound();
+};
 
-    // Opague Enum + TypedEnum
-    forall(E | Serial(T, E)) trait CfaEnum { 
-        char * labelE(E e);
-        unsigned int posE(E e);
-    };
+forall(E | Bounded(E)) trait Serial {
+    unsigned fromInstance(E e);
+    E fromInt(unsigned i);
+    E succ(E e);
+    E pred(E e);
+};
 
-    forall(E| CfaEnum(T, E)) trait TypedEnum {
-        T valueE(E e);
-    };
+// Design one
+forall(E, V | Serial(E)) trait CfaEnum {
+    char* labelE(E e);
+    unsigned int posE(E e);
+    V valueE(E e);
+    char* type_name(E e);
+};
 
-	forall(E | TypedEnum(T, E)) {
-		// comparison
-		int ?==?(E l, E r);								// true if l and r are same enumerators
-		int ?!=?(E l, E r);								// true if l and r are different enumerators
-		int ?!=?(E l, zero_t);							// true if l is not the first enumerator
-		int ?<?(E l, E r);								// true if l is an enuemerator before r
-		int ?<=?(E l, E r);								// true if l before or the same as r
-		int ?>?(E l, E r);								// true if l is an enuemrator after r
-		int ?>=?(E l, E r);								// true if l after or the same as r
-	}
-}
+forall(ostype & | basic_ostream(ostype), E, V| CfaEnum(E, V))
+ostype & ?|?(ostype&, E);
+
+forall(ostype & | basic_ostream(ostype), E| CfaEnum(E, quasi_void))
+ostype & ?|?(ostype&, E);
+
+// Design two <- should go for this if we have change the cost model
+// forall(E | Serial(E)) trait CfaEnum {
+//     char* labelE(E e);
+//     unsigned int posE(E e);
+// };
+
+// forall(E, V| CfaEnum(E)) trait TypedEnum {
+//     V valueE(E e);
+// };
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/AST/Decl.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -170,11 +170,36 @@
 
 const std::string EnumDecl::getUnmangeldArrayName( const ast::EnumAttribute attr ) const {
-		switch( attr ) {
-			case ast::EnumAttribute::Value: return "values_" + name ;
-			case ast::EnumAttribute::Label: return "labels_" + name;
-			default: /* Posn does not generate array */ 
-				return "";
+	switch( attr ) {
+		case ast::EnumAttribute::Value: return "values_" + name ;
+		case ast::EnumAttribute::Label: return "labels_" + name;
+		default: /* Posn does not generate array */ 
+			return "";
+	}
+}
+
+unsigned EnumDecl::calChildOffset(const std::string & target) const{
+	unsigned offset = 0;
+	for (auto childEnum: inlinedDecl) {
+		auto childDecl = childEnum->base;
+		if (childDecl->name == target) {
+			return offset;
 		}
-	}
+		offset += childDecl->members.size();
+	}
+    std::cerr << "Cannot find the target enum" << std::endl;
+	return 0;
+}
+
+unsigned EnumDecl::calChildOffset(const ast::EnumInstType * target) const{
+	return calChildOffset(target->base->name);
+}
+
+bool EnumDecl::isSubTypeOf(const ast::EnumDecl * other) const {
+	if (name == other->name) return true;
+	for (auto inlined: other->inlinedDecl) {
+		if (isSubTypeOf(inlined->base)) return true;
+	}
+	return false;
+}
 
 }
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/AST/Decl.hpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -75,4 +75,5 @@
 	bool isDeleted = false;
 	bool isTypeFixed = false;
+	bool isHidden = false;
 
 	DeclWithType( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
@@ -313,4 +314,6 @@
 	ptr<Type> base;
 	enum class EnumHiding { Visible, Hide } hide;
+	std::vector< ast::ptr<ast::EnumInstType>> inlinedDecl; // child enums
+
 	EnumDecl( const CodeLocation& loc, const std::string& name, bool isTyped = false,
 		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall,
@@ -328,4 +331,9 @@
 
 	const std::string getUnmangeldArrayName( const EnumAttribute attr ) const;
+
+	unsigned calChildOffset(const std::string & childEnum) const;
+	unsigned calChildOffset(const ast::EnumInstType * childEnum) const;
+
+	bool isSubTypeOf(const ast::EnumDecl *) const;
 private:
 	EnumDecl * clone() const override { return new EnumDecl{ *this }; }
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/AST/Expr.hpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -256,8 +256,12 @@
 public:
 	ptr<Decl> type_decl;
-	std::string name;
+	const std::string type_name;
+	const std::string name;
 
 	QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n )
-	: Expr( loc ), type_decl( d ), name( n ) {}
+	: Expr( loc ), type_decl( d ), type_name(""), name( n ) {}
+
+	QualifiedNameExpr( const CodeLocation & loc, const std::string & type_name, const std::string & name)
+	: Expr( loc ), type_name( type_name ), name( name ) {}
 
 	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/AST/Pass.impl.hpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -560,16 +560,9 @@
 
 	if ( __visit_children() ) {
-		if ( node->hide == ast::EnumDecl::EnumHiding::Hide ) {
-			guard_symtab guard { *this };
-			maybe_accept( node, &EnumDecl::base );
-			maybe_accept( node, &EnumDecl::params     );
-			maybe_accept( node, &EnumDecl::members    );
-			maybe_accept( node, &EnumDecl::attributes );
-		} else {
-			maybe_accept( node, &EnumDecl::base );
-			maybe_accept( node, &EnumDecl::params     );
-			maybe_accept( node, &EnumDecl::members    );
-			maybe_accept( node, &EnumDecl::attributes );
-		}
+		maybe_accept( node, &EnumDecl::base        );
+		maybe_accept( node, &EnumDecl::params      );
+		maybe_accept( node, &EnumDecl::members     );
+		maybe_accept( node, &EnumDecl::attributes  );
+		maybe_accept( node, &EnumDecl::inlinedDecl );
 	}
 
Index: src/AST/SymbolTable.cpp
===================================================================
--- src/AST/SymbolTable.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/AST/SymbolTable.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -159,4 +159,16 @@
 }
 
+std::vector<SymbolTable::IdData> SymbolTable::lookupIdIgnoreHidden( const std::string &id ) const {
+	std::vector<IdData> out;
+	std::vector<IdData> lookupResult = lookupId(id);
+	for ( auto candidate: lookupResult) {
+		if ( candidate.id ) {
+			if (candidate.id->isHidden) continue;
+		}
+		out.push_back(candidate);
+	}
+	return out;
+}
+
 std::vector<SymbolTable::IdData> SymbolTable::specialLookupId( SymbolTable::SpecialFunctionKind kind, const std::string & otypeKey ) const {
 	static Stats::Counters::CounterGroup * special_stats = Stats::Counters::build<Stats::Counters::CounterGroup>("Special Lookups");
Index: src/AST/SymbolTable.hpp
===================================================================
--- src/AST/SymbolTable.hpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/AST/SymbolTable.hpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -121,4 +121,6 @@
 	/// Gets all declarations with the given ID
 	std::vector<IdData> lookupId( const std::string &id ) const;
+	/// Gets all declarations with the given ID, ignoring hidden members from enumeration
+	std::vector<IdData> lookupIdIgnoreHidden( const std::string &id ) const;
 	/// Gets special functions associated with a type; if no key is given, returns everything
 	std::vector<IdData> specialLookupId( SpecialFunctionKind kind, const std::string & otypeKey = "" ) const;
Index: src/AST/Util.cpp
===================================================================
--- src/AST/Util.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/AST/Util.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -352,8 +352,6 @@
 	void previsit( EnumDecl const * decl ) {
 		enumDecls.insert( decl );
-		if ( ast::EnumDecl::EnumHiding::Visible == decl->hide ) {
-			for ( auto & member : decl->members ) {
-				typedDecls.insert( member.strict_as<ast::DeclWithType>() );
-			}
+		for ( auto & member : decl->members ) {
+			typedDecls.insert( member.strict_as<ast::DeclWithType>() );
 		}
 		beginScope();
Index: src/GenPoly/Lvalue.cpp
===================================================================
--- src/GenPoly/Lvalue.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/GenPoly/Lvalue.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -389,5 +389,5 @@
 		assert( 0 == diff );
 		// Remove useless generated casts.
-		if ( expr->isGenerated &&
+		if ( expr->isGenerated == ast::GeneratedFlag::GeneratedCast &&
 				ResolvExpr::typesCompatible(
 					expr->result,
@@ -398,4 +398,11 @@
 				std::cerr << "-- " << expr->arg->result << std::endl;
 			)
+			auto argAsEnum = expr->arg.as<ast::EnumInstType>();
+			auto resultAsEnum = expr->result.as<ast::EnumInstType>();
+			if (argAsEnum && resultAsEnum) {
+				if (argAsEnum->base->name != resultAsEnum->base->name) {
+					return expr;
+				}
+			}
 			return ast::mutate_field( expr->arg.get(),
 					&ast::Expr::env, expr->env.get() );
Index: src/Parser/TypeData.cpp
===================================================================
--- src/Parser/TypeData.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/Parser/TypeData.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -1465,11 +1465,11 @@
 	ret->hide = td->aggregate.hiding == EnumHiding::Hide ? ast::EnumDecl::EnumHiding::Hide : ast::EnumDecl::EnumHiding::Visible;
 	for ( const DeclarationNode * cur = td->aggregate.fields ; cur != nullptr ; cur = cur->next, ++members ) {
-		if ( cur->enumInLine ) {
-			// Do Nothing
-		} else if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) {
+		if (cur->enumInLine) continue;
+		ast::Decl * member = members->get_and_mutate();
+		ast::ObjectDecl * object = strict_dynamic_cast<ast::ObjectDecl *>( member );
+		object->isHidden = ast::EnumDecl::EnumHiding::Hide == ret->hide;
+		if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) {
 			SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." );
 		} else if ( cur->has_enumeratorValue() ) {
-			ast::Decl * member = members->get_and_mutate();
-			ast::ObjectDecl * object = strict_dynamic_cast<ast::ObjectDecl *>( member );
 			object->init = new ast::SingleInit(
 				td->location,
@@ -1477,9 +1477,5 @@
 				ast::NoConstruct
 			);
-		} else if ( !cur->initializer ) {
-			if ( baseType && (!dynamic_cast<ast::BasicType *>(baseType) || !dynamic_cast<ast::BasicType *>(baseType)->isInteger())) {
-				SemanticError( td->location, "Enumerators of an non-integer typed enum must be explicitly initialized." );
-			}
-		}
+		} 
 		// else cur is a List Initializer and has been set as init in buildList()
 		// if
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/Parser/parser.yy	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -2827,6 +2827,6 @@
 	| enumerator_list ',' visible_hide_opt identifier_or_type_name enumerator_value_opt
 		{ $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); }
-	| enumerator_list ',' INLINE type_name enumerator_value_opt
-		{ $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); }
+	| enumerator_list ',' INLINE type_name
+		{ $$ = $1->set_last( DeclarationNode::newEnumInLine( $4->symbolic.name )  ); }
 	;
 
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -513,8 +513,25 @@
 					// add new result
 					assert( common );
-						results.emplace_back(
-							i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
-							nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
-					//}
+
+					auto paramAsEnum = dynamic_cast<const ast::EnumInstType *>(paramType);
+					auto argAsEnum =dynamic_cast<const ast::EnumInstType *>(argType);
+					if (paramAsEnum && argAsEnum) {
+						if (paramAsEnum->base->name != argAsEnum->base->name) {
+							Cost c = castCost(argType, paramType, expr, context.symtab, env);
+							if (c < Cost::infinity) {
+								CandidateFinder subFinder( context, env );
+								expr = subFinder.makeEnumOffsetCast(argAsEnum, paramAsEnum, expr, c);
+								results.emplace_back(
+									i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
+									nextArg + 1, nTuples, expl.cost + c, expl.exprs.size() == 1 ? 0 : 1, j );
+								continue;
+							} else {
+								std::cerr << "Cannot instantiate " << paramAsEnum->base->name <<  " with " << argAsEnum->base->name << std::endl;
+							}
+						}
+					}
+					results.emplace_back(
+						i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
+						nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
 				}
 			}
@@ -632,4 +649,8 @@
 			const ast::BaseInstType * aggrInst, const ast::Expr * expr,
 			const Candidate & cand, const Cost & addedCost, const std::string & name
+		);
+
+		void addEnumValueAsCandidate(const ast::EnumInstType * instType, const ast::Expr * expr,
+			const Cost & addedCost
 		);
 
@@ -676,4 +697,8 @@
 		void postvisit( const ast::QualifiedNameExpr * qualifiedExpr );
 
+		const ast::Expr * makeEnumOffsetCast( const ast::EnumInstType * src, 
+			const ast::EnumInstType * dst
+			, const ast::Expr * expr, Cost minCost );
+
 		void postvisit( const ast::InitExpr * ) {
 			assertf( false, "CandidateFinder should never see a resolved InitExpr." );
@@ -876,4 +901,25 @@
 	}
 
+	void Finder::addEnumValueAsCandidate( const ast::EnumInstType * enumInst, const ast::Expr * expr,
+		const Cost & addedCost
+	) {
+		if ( enumInst->base->base ) {
+			CandidateFinder finder( context, tenv );
+			auto location = expr->location;
+			auto callExpr = new ast::UntypedExpr(
+				location, new ast::NameExpr( location, "valueE" ), {expr}
+			);
+			finder.find( callExpr );
+			CandidateList winners = findMinCost( finder.candidates );
+			if (winners.size() != 1) {
+				SemanticError( callExpr, "Ambiguous expression in valueE..." );
+			}
+			CandidateRef & choice = winners.front();
+			choice->cost += addedCost;
+			addAnonConversions(choice);
+			candidates.emplace_back( std::move(choice) );
+		}
+	}
+
 	/// Adds implicit struct-conversions to the alternative list
 	void Finder::addAnonConversions( const CandidateRef & cand ) {
@@ -894,22 +940,8 @@
 			addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );
 		} else if ( auto enumInst = aggrExpr->result.as< ast::EnumInstType >() ) {
-			if ( enumInst->base->base ) {
-				CandidateFinder finder( context, tenv );
-				auto location = aggrExpr->location;
-				auto callExpr = new ast::UntypedExpr(
-					location, new ast::NameExpr( location, "valueE" ), {aggrExpr}
-				);
-				finder.find( callExpr );
-				CandidateList winners = findMinCost( finder.candidates );
-				if (winners.size() != 1) {
-					SemanticError( callExpr, "Ambiguous expression in valueE..." );
-				}
-				CandidateRef & choice = winners.front();
-				choice->cost = Cost::unsafe;
-				candidates.emplace_back( std::move(choice) );
-			}
-
-		}
-	}
+			addEnumValueAsCandidate(enumInst, aggrExpr, Cost::unsafe);
+		}
+	}
+	
 
 	/// Adds aggregate member interpretations
@@ -1180,4 +1212,47 @@
 	}
 
+	// src is a subset of dst
+	const ast::Expr * Finder::makeEnumOffsetCast( const ast::EnumInstType * src, 
+		const ast::EnumInstType * dst,
+		const ast::Expr * expr,
+		Cost minCost ) {
+		
+		auto srcDecl = src->base;
+		auto dstDecl = dst->base;
+
+		if (srcDecl->name == dstDecl->name) return expr;
+
+		for (auto& dstChild: dstDecl->inlinedDecl) {
+			Cost c = castCost(src, dstChild, false, symtab, tenv);
+			ast::CastExpr * castToDst;
+			if (c<minCost) {
+				unsigned offset = dstDecl->calChildOffset(dstChild.get());
+				if (offset > 0) {
+					auto untyped = ast::UntypedExpr::createCall(
+						expr->location, 
+						"?+?", 
+						{ new ast::CastExpr( expr, new ast::BasicType(ast::BasicKind::SignedInt) ),
+						ast::ConstantExpr::from_int(expr->location, offset)});
+					CandidateFinder finder(context, tenv);
+					finder.find( untyped );
+					CandidateList winners = findMinCost( finder.candidates );
+					CandidateRef & choice = winners.front();
+					// choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
+					choice->expr = new ast::CastExpr(expr->location, choice->expr, dstChild, ast::GeneratedFlag::ExplicitCast);
+					// castToDst = new ast::CastExpr(choice->expr, dstChild);
+					castToDst = new ast::CastExpr( 
+						makeEnumOffsetCast( src, dstChild, choice->expr, minCost ),
+					 dst);
+
+				} else {
+					castToDst = new ast::CastExpr( expr, dst );
+				}
+				return castToDst;
+			}
+		}
+		SemanticError(expr, src->base->name + " is not a subtype of " + dst->base->name);
+		return nullptr;
+	}
+
 	void Finder::postvisit( const ast::CastExpr * castExpr ) {
 		ast::ptr< ast::Type > toType = castExpr->result;
@@ -1229,4 +1304,12 @@
 					? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
 					: castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
+			
+			// Redefine enum cast
+			auto argAsEnum = cand->expr->result.as<ast::EnumInstType>();
+			auto toAsEnum = toType.as<ast::EnumInstType>();
+			if ( argAsEnum && toAsEnum && argAsEnum->name != toAsEnum->name ) {	
+				ast::ptr<ast::Expr> offsetExpr = makeEnumOffsetCast(argAsEnum, toAsEnum, cand->expr, thisCost);
+				cand->expr = offsetExpr;
+			}
 
 			PRINT(
@@ -1246,8 +1329,6 @@
 					minCastCost = thisCost;
 					matches.clear();
-
-
-				}
-				// ambiguous case, still output candidates to print in error message
+				}
+				// ambigious case, still output candidates to print in error message
 				if ( cand->cost == minExprCost && thisCost == minCastCost ) {
 					CandidateRef newCand = std::make_shared<Candidate>(
@@ -1264,5 +1345,4 @@
 		}
 		candidates = std::move(matches);
-
 		//CandidateList minArgCost = findMinCost( matches );
 		//promoteCvtCost( minArgCost );
@@ -1374,5 +1454,5 @@
 			}
 		} else {
-			declList = symtab.lookupId( nameExpr->name );
+			declList = symtab.lookupIdIgnoreHidden( nameExpr->name );
 		}
 		PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
@@ -1386,14 +1466,4 @@
 			ast::Expr * newExpr = data.combine( nameExpr->location, cost );
 
-			// bool bentConversion = false;
-			// if ( auto inst = newExpr->result.as<ast::EnumInstType>() ) {
-			// 	if ( inst->base && inst->base->base ) {
-			// 		bentConversion = true;
-			// 	}
-			// }
-
-			// CandidateRef newCand = std::make_shared<Candidate>(
-			// 	newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, bentConversion? Cost::safe: Cost::zero,
-			// 	cost );
 			CandidateRef newCand = std::make_shared<Candidate>(
 				newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
@@ -1813,12 +1883,8 @@
 			if ( const ast::EnumInstType * enumInstType =
 				dynamic_cast<const ast::EnumInstType *>( t ) ) {
-				if ( enumInstType->base->name == expr->type_decl->name ) {
+				if ( (enumInstType->base->name == expr->type_name)
+					|| (expr->type_decl && enumInstType->base->name == expr->type_decl->name) ) {
 					Cost cost = Cost::zero;
 					ast::Expr * newExpr = data.combine( expr->location, cost );
-					// CandidateRef newCand =
-					// 	std::make_shared<Candidate>(
-					// 		newExpr, copy( tenv ), ast::OpenVarSet{},
-					// 		ast::AssertionSet{}, Cost::safe, cost
-					// 	);
 					CandidateRef newCand =
 						std::make_shared<Candidate>(
@@ -2096,4 +2162,43 @@
 
 	return expr;
+}
+
+const ast::Expr * CandidateFinder::makeEnumOffsetCast( const ast::EnumInstType * src, 
+	const ast::EnumInstType * dst,
+	const ast::Expr * expr,
+	Cost minCost ) {
+	
+	auto srcDecl = src->base;
+	auto dstDecl = dst->base;
+
+	if (srcDecl->name == dstDecl->name) return expr;
+
+	for (auto& dstChild: dstDecl->inlinedDecl) {
+		Cost c = castCost(src, dstChild, false, context.symtab, env);
+		ast::CastExpr * castToDst;
+		if (c<minCost) {
+			unsigned offset = dstDecl->calChildOffset(dstChild.get());
+			if (offset > 0) {
+				auto untyped = ast::UntypedExpr::createCall(
+					expr->location, 
+					"?+?", 
+					{ new ast::CastExpr( expr, new ast::BasicType(ast::BasicKind::SignedInt) ),
+					ast::ConstantExpr::from_int(expr->location, offset)});
+				CandidateFinder finder(context, env);
+				finder.find( untyped );
+				CandidateList winners = findMinCost( finder.candidates );
+				CandidateRef & choice = winners.front();
+				choice->expr = new ast::CastExpr(expr->location, choice->expr, dstChild, ast::GeneratedFlag::ExplicitCast);
+				castToDst = new ast::CastExpr( 
+					makeEnumOffsetCast( src, dstChild, choice->expr, minCost ),
+					dst);
+			} else {
+				castToDst = new ast::CastExpr( expr, dst );
+			}
+			return castToDst;
+		}
+	}
+	SemanticError(expr, src->base->name + " is not a subtype of " + dst->base->name);
+	return nullptr;
 }
 
Index: src/ResolvExpr/CandidateFinder.hpp
===================================================================
--- src/ResolvExpr/CandidateFinder.hpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/ResolvExpr/CandidateFinder.hpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -58,4 +58,7 @@
 	iterator end() { return candidates.end(); }
 	const_iterator end() const { return candidates.end(); }
+
+	const ast::Expr * makeEnumOffsetCast( const ast::EnumInstType * src, 
+		const ast::EnumInstType * dst, const ast::Expr * expr, Cost minCost );
 };
 
Index: src/ResolvExpr/CastCost.cpp
===================================================================
--- src/ResolvExpr/CastCost.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/ResolvExpr/CastCost.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -36,4 +36,9 @@
 namespace ResolvExpr {
 
+Cost castCost(
+	const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+);
+
 namespace {
 	struct CastCost : public ConversionCost {
@@ -45,4 +50,8 @@
 			const ast::TypeEnvironment & env, CostCalculation costFunc )
 		: ConversionCost( dst, srcIsLvalue, symtab, env, costFunc ) {}
+
+		void postvisit( const ast::EnumInstType * enumInst ) {
+			cost = conversionCost( enumInst, dst, srcIsLvalue, symtab, env );
+		}
 
 		void postvisit( const ast::BasicType * basicType ) {
@@ -104,10 +113,4 @@
 					cost = Cost::unsafe;
 				}
-			}
-		}
-
-		void postvist( const ast::EnumInstType * ) {
-			if ( auto basic = dynamic_cast< const ast::BasicType * >(dst) ) {
-				if ( basic->isInteger() ) cost = Cost::unsafe;
 			}
 		}
Index: src/ResolvExpr/CommonType.cpp
===================================================================
--- src/ResolvExpr/CommonType.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/ResolvExpr/CommonType.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -636,6 +636,11 @@
 	void postvisit( const ast::UnionInstType * ) {}
 
-	void postvisit( const ast::EnumInstType * enumInst ) {
-		if ( enumInst->base && !enumInst->base->isTyped ) {
+	void postvisit( const ast::EnumInstType * param ) {
+		auto argAsEnumInst = dynamic_cast<const ast::EnumInstType *>(type2);
+		if ( argAsEnumInst ) {
+			const ast::EnumDecl* paramDecl = param->base;
+			const ast::EnumDecl* argDecl = argAsEnumInst->base;
+			if (argDecl->isSubTypeOf(paramDecl)) result = param;
+		} else if ( param->base && !param->base->isTyped ) {
 			auto basicType = new ast::BasicType( ast::BasicKind::UnsignedInt );
 			result = commonType( basicType, type2, tenv, need, have, open, widen);
Index: src/ResolvExpr/ConversionCost.cpp
===================================================================
--- src/ResolvExpr/ConversionCost.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/ResolvExpr/ConversionCost.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -191,4 +191,9 @@
 }
 
+Cost enumCastCost (
+	const ast::EnumInstType * src, const ast::EnumInstType * dst, 
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+);
+
 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
 		int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
@@ -359,11 +364,6 @@
 
 void ConversionCost::postvisit( const ast::EnumInstType * inst ) {
-	if ( auto dstAsInst = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
-		if (inst->base && dstAsInst->base) {
-			if (inst->base->name == dstAsInst->base->name) {
-				cost = Cost::zero;
-				return;
-			}
-		}
+	if ( auto dstInst = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
+		cost = enumCastCost(inst, dstInst, symtab, env);
 		return;
 	}
@@ -481,4 +481,21 @@
 }
 
+// (dst) src is safe is src is a subtype of dst, or dst {inline src, ...}
+Cost enumCastCost (
+	const ast::EnumInstType * src, const ast::EnumInstType * dst, 
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+) {
+	auto srcDecl = src->base;
+	auto dstDecl = dst->base;
+	if (srcDecl->name == dstDecl->name) return Cost::safe;
+	Cost minCost = Cost::infinity;
+	for (auto child: dstDecl->inlinedDecl) {
+		Cost c = enumCastCost(src, child, symtab, env) + Cost::safe;
+		if (c<minCost) minCost = c;
+	}
+	return minCost;
+}
+
+
 // size_t ConversionCost::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
 
Index: src/ResolvExpr/Resolver.cpp
===================================================================
--- src/ResolvExpr/Resolver.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/ResolvExpr/Resolver.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -201,4 +201,12 @@
 				&& typesCompatible( castExpr->arg->result, castExpr->result )
 			) {
+				auto argAsEnum = castExpr->arg.as<ast::EnumInstType>();
+				auto resultAsEnum = castExpr->result.as<ast::EnumInstType>();
+				if (argAsEnum && resultAsEnum) {
+					if (argAsEnum->base->name != resultAsEnum->base->name) {
+						std::cerr << "Enum Cast: " << argAsEnum->base->name << " to " << resultAsEnum->base->name << std::endl;
+						return castExpr;
+					}
+				}
 				// generated cast is the same type as its argument, remove it after keeping env
 				return ast::mutate_field(
Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/Validate/Autogen.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -410,5 +410,5 @@
 }
 
-/// Use the current type T to create `T ?{}(T & _dst, T _src)`.
+/// Use the current type T to create `T ?=?(T & _dst, T _src)`.
 ast::FunctionDecl * FuncGenerator::genAssignProto() const {
 	// Only the name is different, so just reuse the generation function.
Index: src/Validate/EnumAndPointerDecay.cpp
===================================================================
--- src/Validate/EnumAndPointerDecay.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/Validate/EnumAndPointerDecay.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -47,21 +47,26 @@
 				new ast::EnumInstType( decl, ast::CV::Const ) ) );
 		} else if ( auto value = member.as<ast::InlineMemberDecl>() ) {
-			if ( auto targetEnum = symtab.lookupEnum( value->name ) ) {
-				for ( auto enumMember : targetEnum->members ) {
-					auto enumObject = enumMember.strict_as<ast::ObjectDecl>();
-					buffer.push_back( new ast::ObjectDecl(
-						// Get the location from the "inline" declaration.
-						value->location,
-						enumObject->name,
-						// Construct a new EnumInstType as the type.
-						new ast::EnumInstType( decl, ast::CV::Const ),
-						enumObject->init,
-						enumObject->storage,
-						enumObject->linkage,
-						enumObject->bitfieldWidth,
-						{},
-						enumObject->funcSpec
-					) );
-				}
+			auto targetEnum = symtab.lookupEnum( value->name );
+			// assert( targetEnum );
+			if (!targetEnum) {
+				SemanticError(value, "Only another enum is allowed for enum inline syntax ");
+			}
+			const ast::EnumInstType * instType = new ast::EnumInstType(targetEnum);
+			mut->inlinedDecl.push_back( std::move(instType) );
+			for ( auto enumMember : targetEnum->members ) {
+				auto enumObject = enumMember.strict_as<ast::ObjectDecl>();
+				buffer.push_back(new ast::ObjectDecl(
+					// Get the location from the "inline" declaration.
+					value->location,
+					enumObject->name,
+					// Construct a new EnumInstType as the type.
+					new ast::EnumInstType( decl, ast::CV::Const ),
+					enumObject->init,
+					enumObject->storage,
+					enumObject->linkage,
+					enumObject->bitfieldWidth,
+					{},
+					enumObject->funcSpec
+				));
 			}
 		}
Index: src/Validate/ImplementEnumFunc.cpp
===================================================================
--- src/Validate/ImplementEnumFunc.cpp	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ src/Validate/ImplementEnumFunc.cpp	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -10,4 +10,5 @@
 	const ast::EnumDecl* decl;
 	unsigned int functionNesting;
+	const ast::StructDecl* quasi_void_decl;
 	ast::Linkage::Spec proto_linkage;
 
@@ -24,4 +25,7 @@
 		: decl(decl),
 		  functionNesting{functionNesting},
+		  quasi_void_decl(new ast::StructDecl(decl->location, 
+		  	"quasi_void", ast::AggregateDecl::Struct,
+			{}, ast::Linkage::AutoGen)),
 		  proto_linkage{ast::Linkage::Cforall} {}
 
@@ -52,4 +56,6 @@
 	void genSuccPredBody(ast::FunctionDecl *, const char *) const;
 
+	void genTypeNameFunc();
+
 	// Implement TypedEnum trait
 	void genTypedEnumFuncs();
@@ -58,17 +64,12 @@
 	ast::FunctionDecl* genLabelProto() const;
 	ast::FunctionDecl* genValueProto() const;
+	ast::FunctionDecl* genQuasiValueProto() const;
+	ast::FunctionDecl* genTypeNameProto() const;
+
 	void genValueOrLabelBody(
 		ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
 	void genPosnBody(ast::FunctionDecl* func) const;
-
-	////////////////
-
-	// ---------------------------------------------------
-	// ast::FunctionDecl* genAttrCtorProto() const;
-	/// Changes the node inside a pointer so that it has the unused attribute.
-	void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
-		ast::DeclWithType* decl = declPtr.get_and_mutate();
-		decl->attributes.push_back(new ast::Attribute("unused"));
-	}
+	void genQuasiValueBody(ast::FunctionDecl* func) const;
+	void genTypeNameBody(ast::FunctionDecl* func) const;
 
 	// ----------------------------------------------------
@@ -117,4 +118,5 @@
 	return inits;
 }
+
 const ast::Init* EnumAttrFuncGenerator::getAutoInit(
 	const ast::Init* prev) const {
@@ -189,9 +191,20 @@
 
 ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
+	if (decl->base)
+		return genProto(
+			"valueE",
+			{new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
+			{new ast::ObjectDecl(getLocation(), "_ret",
+								ast::deepCopy(decl->base))});
+	else
+		return genQuasiValueProto();
+}
+
+ast::FunctionDecl* EnumAttrFuncGenerator::genQuasiValueProto() const {
 	return genProto(
 		"valueE",
 		{new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
 		{new ast::ObjectDecl(getLocation(), "_ret",
-		                     ast::deepCopy(decl->base))});
+		                		new ast::StructInstType(quasi_void_decl))});
 }
 
@@ -210,4 +223,13 @@
 		{new ast::ObjectDecl(getLocation(), "_ret", new ast::BasicType(ast::BasicKind::UnsignedInt))}
 	);
+}
+
+ast::FunctionDecl* EnumAttrFuncGenerator::genTypeNameProto() const {
+	return genProto(
+		"type_name",
+		{new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
+		{new ast::ObjectDecl(
+			getLocation(), "_ret",
+			new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
 }
 
@@ -268,5 +290,4 @@
 	);
 }
-
 
 void EnumAttrFuncGenerator::genSerialTraitFuncs() {
@@ -302,5 +323,6 @@
 	const CodeLocation & loc = func->location;
 	auto mem = func->name=="lowerBound"?  decl->members.front() : decl->members.back();
-	auto expr = new ast::NameExpr( loc, mem->name );
+	// auto expr = new ast::NameExpr( loc, mem->name );
+	auto expr = new ast::QualifiedNameExpr( loc, decl->name, mem->name );
 	func->stmts = new ast::CompoundStmt( loc, {new ast::ReturnStmt(loc, expr)});
 }
@@ -349,4 +371,17 @@
 }
 
+void EnumAttrFuncGenerator::genQuasiValueBody(ast::FunctionDecl* func) const {
+	auto location = func->location;
+	const ast::ObjectDecl * objDecl = new ast::ObjectDecl(
+		location, "_out", new ast::StructInstType( quasi_void_decl ));
+	const ast::DeclStmt * declStmt = new ast::DeclStmt(location, objDecl);
+	const ast::VariableExpr * varExpr = new ast::VariableExpr(location, objDecl);
+	const ast::ReturnStmt * retStmt = new ast::ReturnStmt(location, varExpr);
+
+	func->stmts = new ast::CompoundStmt(
+		location, {declStmt, retStmt}
+	);
+}
+
 void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
 	auto castExpr = new ast::CastExpr(
@@ -359,17 +394,36 @@
 }
 
+void EnumAttrFuncGenerator::genTypeNameBody(ast::FunctionDecl* func) const {
+	const ast::Expr * type_name = ast::ConstantExpr::from_string(func->location, decl->name);
+	func->stmts = new ast::CompoundStmt(
+		func->location, {new ast::ReturnStmt(func->location, type_name)}
+	);
+}
+
 void EnumAttrFuncGenerator::genTypedEnumFunction(const ast::EnumAttribute attr) {
-	if (attr == ast::EnumAttribute::Value ||
-		attr == ast::EnumAttribute::Label) {
-		// TypedEnum's backing arrays
-		std::vector<ast::ptr<ast::Init>> inits =
-			attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
+	if (attr == ast::EnumAttribute::Value) {
+		if (decl->base) {
+			// TypedEnum's backing arrays
+			std::vector<ast::ptr<ast::Init>> inits = genValueInit();
+			ast::ObjectDecl* arrayProto =
+				genAttrArrayProto(attr, getLocation(), inits);
+			forwards.push_back(arrayProto);
+
+			ast::FunctionDecl* funcProto = genValueProto();
+			produceForwardDecl(funcProto);
+			genValueOrLabelBody(funcProto, arrayProto);
+			produceDecl(funcProto);
+		}  else {
+			ast::FunctionDecl* funcProto = genQuasiValueProto();
+			produceForwardDecl(funcProto);
+			genQuasiValueBody(funcProto);
+			produceDecl(funcProto);
+		}
+	} else if (attr == ast::EnumAttribute::Label) {
+		std::vector<ast::ptr<ast::Init>> inits = genLabelInit();
 		ast::ObjectDecl* arrayProto =
 			genAttrArrayProto(attr, getLocation(), inits);
 		forwards.push_back(arrayProto);
-
-		ast::FunctionDecl* funcProto = ( attr == ast::EnumAttribute::Value )
-		                               ? genValueProto()
-		                               : genLabelProto();
+		ast::FunctionDecl* funcProto = genLabelProto();
 		produceForwardDecl(funcProto);
 		genValueOrLabelBody(funcProto, arrayProto);
@@ -384,7 +438,14 @@
 
 void EnumAttrFuncGenerator::genTypedEnumFuncs() {
-	if (decl->base) genTypedEnumFunction(ast::EnumAttribute::Value);
+	genTypedEnumFunction(ast::EnumAttribute::Value);
 	genTypedEnumFunction(ast::EnumAttribute::Label);
 	genTypedEnumFunction(ast::EnumAttribute::Posn);
+}
+
+void EnumAttrFuncGenerator::genTypeNameFunc() {
+	ast::FunctionDecl* funcProto = genTypeNameProto();
+	produceForwardDecl(funcProto);
+	genTypeNameBody(funcProto);
+	produceDecl(funcProto);
 }
 
@@ -392,4 +453,5 @@
 	std::list<ast::ptr<ast::Decl>>& decls) {
 	// Generate the functions (they go into forwards and definitions).
+	genTypeNameFunc();
 	genTypedEnumFuncs();
 	genSerialTraitFuncs();
Index: tests/enum_tests/.expect/enumInlineValue.txt
===================================================================
--- tests/enum_tests/.expect/enumInlineValue.txt	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ tests/enum_tests/.expect/enumInlineValue.txt	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -1,4 +1,22 @@
-enumB.A is 5
-enumB.B is 6
-enumB.D is 11
-enumB.E is 12
+Symbols (enumerator) should have the same values:
+Symbol a: (10) 10, 10, 10
+Symbol b: (20) 20, 20
+Symbol ab: (30) 30
+Symbol c: (40) 40, 40, 40
+Symbol d: (50) 50, 50, 50
+Symbol cd: (60) 60, 60
+Symbol acd: (70) 70
+Casting/Upcasting:
+Symbol a: (10) 10, 10, 10
+Symbol b: (20) 20, 20
+Symbol ab: (30) 30
+Symbol c: (40) 40, 40, 40, 40, 40
+Symbol d: (50) 50, 50, 50, 50
+Symbol cd: (60) 60, 60
+Symbol acd: (70) 70
+Function Call:
+Symbol a: (10) 10, 10
+Symbol c: (40) 40, 40
+Symbol d: (50) 50, 50
+Symbol cd: (60) 60, 60
+Symbol acd: (70) 70
Index: tests/enum_tests/enumInlineValue.cfa
===================================================================
--- tests/enum_tests/enumInlineValue.cfa	(revision d68de591a95316294f328c176c7f3ac614713722)
+++ tests/enum_tests/enumInlineValue.cfa	(revision 85855b0f02c6f17de398969fbe7ab4810d76737a)
@@ -2,5 +2,5 @@
 #include <enum.hfa>
 
-enum(int) A {
+enum(int) A !{
     a = 10
 };
@@ -36,6 +36,9 @@
 };
 
-int identity(A a) {
-    return valueE(a);
+// Note: variable name (cat in this case) cannot be overloaded with those declared in enum,
+// Probably for the same reason as const overloading problem
+// i.e. int identity_t(enum ACD a) would not work as the valueE(a) is ambigious currently
+int identity_t(enum ACD cat) {
+    return valueE(cat);
 }
 
@@ -43,26 +46,27 @@
     // Note: We need to use qualified name syntax even if no ! hidding
     // Because Inline introduce ambiguity on symbols
-    // sout | "Symbols (enumerator) should have the same values:" |nl;
-    // sout | "Symbol a: (10) " | valueE(A.a) | "," | valueE(AB.a) | "," | valueE(ACD.a) | nl;
-    // sout | "Symbol b: (20) " | valueE(B.b) | "," | valueE(AB.b) | nl;
-    // sout | "Symbol ab: (30) " | valueE(AB.ab) | nl;
-    // sout | "Symbol c: (40) " | valueE(C.c) | "," | valueE(CD.c) | "," | valueE(ACD.c) | nl;
-    // sout | "Symbol d: (50) " | valueE(D.d) | "," | valueE(CD.d) | "," | valueE(ACD.d) | nl;
-    // sout | "Symbol cd: (60) " | valueE(CD.cd) | "," | valueE(ACD.cd) | nl;
-    // sout | "Symbol acd: (70) " | valueE(ACD.acd) | nl;
+    sout | "Symbols (enumerator) should have the same values:" |nl;
+    sout | "Symbol a: (10) " | valueE(A.a) | "," | valueE(AB.a) | "," | valueE(ACD.a) | nl;
+    sout | "Symbol b: (20) " | valueE(B.b) | "," | valueE(AB.b) | nl;
+    sout | "Symbol ab: (30) " | valueE(AB.ab) | nl;
+    sout | "Symbol c: (40) " | valueE(C.c) | "," | valueE(CD.c) | "," | valueE(ACD.c) | nl;
+    sout | "Symbol d: (50) " | valueE(D.d) | "," | valueE(CD.d) | "," | valueE(ACD.d) | nl;
+    sout | "Symbol cd: (60) " | valueE(CD.cd) | "," | valueE(ACD.cd) | nl;
+    sout | "Symbol acd: (70) " | valueE(ACD.acd) | nl;
 
-    // sout | "Casting/Upcasting:" | nl;
-    // sout | "Symbol a: (10) " | valueE((A)A.a) | "," | valueE((AB)A.a) | "," | valueE((ACD)A.a) | nl;
-    // sout | "Symbol b: (20) " | valueE((B)B.b) | "," | valueE((AB)B.b) | nl;
-    // sout | "Symbol ab: (30) " | valueE((AB)AB.ab) | nl;
-    // sout | "Symbol c: (40) " | valueE((C)C.c) | "," | valueE((CD)C.c) | "," | valueE((ACD)C.c) | "," | valueE((CD)CD.c)| "," | valueE((ACD)CD.c) | nl;
-    // sout | "Symbol d: (50) " | valueE((D)D.d) | "," | valueE((CD)D.d) | "," | valueE((ACD)D.d) | "," | valueE((ACD)CD.d) | nl;
-    // sout | "Symbol cd: (60) " | valueE((CD)CD.cd) | "," | valueE((ACD)CD.cd) | nl;
-    // sout | "Symbol acd: (70) " | valueE((ACD)ACD.acd) | nl;
+    sout | "Casting/Upcasting:" | nl;
+    sout | "Symbol a: (10) " | valueE((A)A.a) | "," | valueE((AB)A.a) | "," | valueE((ACD)A.a) | nl;
+    sout | "Symbol b: (20) " | valueE((B)B.b) | "," | valueE((AB)B.b) | nl;
+    sout | "Symbol ab: (30) " | valueE((AB)AB.ab) | nl;
+    sout | "Symbol c: (40) " | valueE((C)C.c) | "," | valueE((CD)C.c) | "," | valueE((ACD)C.c) | "," | valueE((CD)CD.c)| "," | valueE((ACD)CD.c) | nl;
+    sout | "Symbol d: (50) " | valueE((D)D.d) | "," | valueE((CD)D.d) | "," | valueE((ACD)D.d) | "," | valueE((ACD)CD.d) | nl;
+    sout | "Symbol cd: (60) " | valueE((CD)CD.cd) | "," | valueE((ACD)CD.cd) | nl;
+    sout | "Symbol acd: (70) " | valueE((ACD)ACD.acd) | nl;
 
-    // sout | "Function Call:" | nl;
-    // sout | "Symbol a: (10) " | identity(A.a) | "," | identity(ACD.a);
-    // sout | "Symbol c: (40) " | identity(C.c) | "," | identity(CD.c)| "," | identity(ACD.c);
-    identity(A.a);
-
+    sout | "Function Call:" | nl;
+    sout | "Symbol a: (10) " | identity_t(A.a) | "," | identity_t(ACD.a) | nl;
+    sout | "Symbol c: (40) " | identity_t(C.c) | "," | identity_t(ACD.c) | nl;
+    sout | "Symbol d: (50) " | identity_t(D.d) | "," | identity_t(ACD.d) | nl;
+    sout | "Symbol cd: (60) " | identity_t(CD.cd) | "," | identity_t(ACD.cd) | nl;
+    sout | "Symbol acd: (70) " | identity_t(ACD.acd) | nl;
 }
