Skip to content

Instantly share code, notes, and snippets.

@jneira
Last active January 18, 2017 21:10
Show Gist options
  • Save jneira/25b8eb0c417c0e94a871132f30314ea9 to your computer and use it in GitHub Desktop.
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
@jmhdez
Copy link

jmhdez commented Jan 18, 2017

No acabo de entender qué aporta el ejemplo en Java.

Al final, lo que comprueba el compilador es que getPermission devuelve un Permission<T> con T igual al de la clase que implementa en getPermission, pero eso me permitiría hacer:

public static class FooView implements View<FooView> {
  @Override
  public Permission<FooView> getPermission() {
    return new Permission<FooView>();                        // Uso Permission
  }
 }
 
 public static class BarView implements View<BarView> {
  @Override
  public Permission<BarView> getPermission() { // Esto no compila
    return new Permission<BarView>();                       // El mismo Permission
  }	 
}

¿Qué gano teniendo N clases permission para simular un tipo suma, si al final puedo acabar usando siempre la misma?

@jneira
Copy link
Author

jneira commented Jan 18, 2017

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
		}
		 
	 }
}

@jneira
Copy link
Author

jneira commented Jan 18, 2017

Perdon, la opcion sera en java hacer el constructor privado, si haces la clase privada no puedes usarla fuera al crear Views

@jmhdez
Copy link

jmhdez commented Jan 18, 2017

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.

@jneira
Copy link
Author

jneira commented Jan 18, 2017

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment