-
-
Save jneira/25b8eb0c417c0e94a871132f30314ea9 to your computer and use it in GitHub Desktop.
// simular las typeclasses Enum y Bounded de haskell | |
interface Bounded<T> { | |
minBound: T | |
maxBound: T | |
} | |
interface Enum<T> { | |
fromEnum(number): T | |
toEnum(T): number | |
} | |
abstract class PermissionEnum { | |
static minBound = Perm1 | |
static maxBound = Perm2 | |
static all = [Perm1,Perm2] | |
static fromEnum(p: Permission<any>): number { | |
let res = PermissionEnum.all.findIndex(function (p1) { return p1 == p }) | |
if (!res) throw new Error | |
return res; | |
} | |
static toEnum(i:number): Permission<any> { | |
let res = PermissionEnum.all[i] | |
if (!res) throw new Error | |
return res; | |
} | |
} | |
class Perm1<T> extends PermissionEnum { } | |
class Perm2<T> extends PermissionEnum { } | |
type Permission<T> = Perm1<T> | Perm2<T> | |
interface View { | |
} | |
class FooView implements View { | |
static permission: Permission<FooView> = new Perm1<FooView>() | |
} | |
type ViewClassWithPerm<V extends View>= {new(props:any):V} & {permission:Permission<V>} | |
function registerView<V extends View>(v : ViewClassWithPerm<V>) { | |
alert(v) | |
alert | |
} | |
registerView<FooView>(FooView) | |
class BarView implements View { | |
static permission: Permission<FooView> = new Perm1<FooView>() | |
} | |
registerView<BarView>(BarView) // Esto no deberia compilar ya que new(): BarView y permission:FooView |
public class Prueba { | |
private static abstract class Permission<T> { | |
} | |
public final static class Perm1<T> extends Permission<T> { | |
} | |
public final static class Perm2<T> extends Permission<T> { | |
} | |
public static interface View<V extends View<V>> { | |
Permission<V> getPermission(); | |
} | |
public static class FooView implements View<FooView> { | |
@Override | |
public Permission<FooView> getPermission() { | |
return new Perm1<FooView>(); | |
} | |
} | |
public static class BarView implements View<BarView> { | |
@Override | |
public Permission<FooView> getPermission() { // Esto no compila | |
return new Perm1<FooView>(); | |
} | |
} | |
} |
class Perm1<T> { } | |
class Perm2<T> { } | |
type Permission<T> = Perm1<T> | Perm2<T> | |
interface View { | |
} | |
class FooView implements View { | |
static permission: Permission<FooView> = new Perm1<FooView>() | |
} | |
type ViewClassWithPerm<V extends View>= {new(props:any):V} & {permission:Permission<V>} | |
function registerView<V extends View>(v : ViewClassWithPerm<V>) { | |
alert(v) | |
} | |
registerView<FooView>(FooView) | |
class BarView implements View { | |
static permission: Permission<FooView> = new Perm1<FooView>() | |
} | |
registerView<BarView>(BarView) // Esto no deberia compilar ya que new(): BarView y permission:FooView |
class Perm1<T> { } | |
class Perm2<T> { } | |
type Permission<T> = Perm1<T> | Perm2<T> | |
interface View<V extends View<V>> { | |
permission:Permission<V> | |
} | |
class FooView implements View<FooView> { | |
permission: Permission<FooView> = new Perm1<FooView>() | |
} | |
function registerView<V extends View<V>>(v : V) { | |
alert(v) | |
} | |
registerView<FooView>(new FooView()) | |
class BarView implements View<BarView> { // Esto no deberia cooompilar, en java no compila | |
permission: Permission<FooView> = new Perm1<FooView>() | |
} | |
registerView<BarView>(new BarView()) |
module View where | |
class WithPermission a where | |
permission :: a -> Permission | |
data Permission = Perm1 | Perm2 | |
deriving Show | |
data View = FooView | BarView | |
instance WithPermission View where | |
permission FooView = Perm1 | |
permission BarView = Perm2 | |
-- En haskell la relacion entre view y permission esta separada y no hay problema de copy paste |
Justo habia editado el ejemplo para hacer Permission private y que no sea accesible directamente, en tu ejemplo tendrias que crear clases anonimas ya que es abstracta, pero se podria hacer:
return new Permission<FooView>() {};
Aparte de hacerla privada podrias hacer el constructor private
Aun asi eso no te libraria de
public static class BarView implements View<FooView> {
@Override
public Permission<FooView> getPermission() { // Esto si compila
return new Perm1<FooView>();
}
}
pero podrias hacer un doble check sobre el view, si se lo salta es para pegarle con un calcetin sudao
private static abstract class ViewChecked<V extends ViewChecked<V>> implements View<V> {
public abstract V getInstance() ;
}
public static class FooView extends ViewChecked<FooView> {
@Override
public Permission<FooView> getPermission() {
return new Perm1<FooView>();
}
@Override
public FooView getInstance() {
return this;
}
}
public static class BarView extends ViewChecked<FooView> {
@Override
public Permission<FooView> getPermission() {
return new Perm1<FooView>();
}
@Override
public FooView getInstance() {
return this; // no compila, si lo cambia por new FooView(), lo corres a gorrazos
}
}
}
Perdon, la opcion sera en java hacer el constructor privado, si haces la clase privada no puedes usarla fuera al crear Views
La parte de correr a gorrazos siempre puede funcionar, pero yo no soy especialmente rápido y seguramente el que se equivoque (a menos que sea yo mismo), consiga eludirme.
Aunque me quite el Permission
publico, sigo pudiendo hacer new Perm1<FooView>()
en un sitio y new Perm2<BarView>
en otro.
Podríamos discutir si tiene sentido separar View
y Permission
si la relación entre ellos es tan estrecha, y si podríamos asimilar el uno a la otra, pero en la realidad los Permission
aparecen en partes del sistema donde no quiero que aparezcan Views
, por lo que me gustaría mantenerlos como conceptos separados.
La solucion quizas iria por crear un PermissionView<V extends View,P extends Permission> y dejar publicas y finales (o hacerlas singletons) justo las clases que harian la biyeccion a nivel de tipo
No acabo de entender qué aporta el ejemplo en Java.
Al final, lo que comprueba el compilador es que
getPermission
devuelve unPermission<T>
conT
igual al de la clase que implementa engetPermission
, pero eso me permitiría hacer:¿Qué gano teniendo N clases permission para simular un tipo suma, si al final puedo acabar usando siempre la misma?