我需要帮助了解我当前的OOP状态概念与在Haskell或Clojure等函数语言中完成的方式之间的区别.
使用一个陈腐的例子,假设我们正在处理简化的银行账户对象/结构/任何事情.在OOP语言中,我有一些类持有对BankAccount的引用,BankAccount将具有诸如利率之类的事件的实例变量,以及诸如setInterestRate()之类的方法,其改变对象的状态并且通常不返回任何内容.在说Clojure中,我有一个银行账户结构(一个美化的散列图),以及带有银行账户参数和其他信息的特殊函数,并返回一个新的结构.因此,我现在不再更改原始对象的状态,而是返回一个具有所需修改的新对象.
那么......我该怎么办呢?覆盖引用旧银行帐户的任何变量?如果是这样,那是否比改变状态的OOP方法有优势?最后,在这两种情况下,似乎有一个变量引用具有必要更改的对象.像我一样迟钝,我对发生的事情只有一个模糊的概念.
我希望这是有道理的,谢谢你的帮助!
language-agnostic oop comparison functional-programming immutability
在我的函数内部,我通过用数据填充新的可变HashMap来构造结果集(如果有更好的方法 - 我很感激评论).然后我想将结果集作为不可变的HashMap返回.如何从变量中导出一个不可变的?
ImmutableSet在我的基准测试中,番石榴似乎表现不佳contains.对于某些尺寸,它甚至比List以下更慢:
size benchmark ns linear runtime
100000 ListContains 110279.54 ==
100000 SetContains 7.15 =
100000 ImmutableSetContains 76716.47 =
200000 ListContains 275367.66 =====
200000 SetContains 7.34 =
200000 ImmutableSetContains 322185.50 ======
500000 ListContains 935210.10 ====================
500000 SetContains 7.79 =
500000 ImmutableSetContains 1382765.76 ==============================
Run Code Online (Sandbox Code Playgroud)
基本上,我填充一组有几千个负整数,测试包含非负数.代码很简单,但在一个小的文本区域粘贴有点太长,所以请看这里.
我想知道这里发生了什么.可能,我遇到了一些堕落的情况,尽管我显然没有尝试过.或许我刚刚吹了基准.否则,我想知道它是否可以而且应该修复.
解决方案是通过替换来改变拖尾功能
hashCode ^= (hashCode >>> 20) ^ (hashCode >>> 12);
return hashCode ^ (hashCode >>> 7) ^ (hashCode >>> 4);
Run Code Online (Sandbox Code Playgroud)
通过
return C2 * Integer.rotateLeft(hashCode * C1, …Run Code Online (Sandbox Code Playgroud) 根据JSR-133,不可变对象是线程安全的,不需要同步.但是,可以使用反射更新最终字段的值:
package com.stackoverflow;
import java.lang.reflect.Field;
public class WhatsGoingOn {
static class Immutable {
private final int value;
public Immutable(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
final Immutable immutable = new Immutable(Integer.MIN_VALUE);
final Field f = Immutable.class.getDeclaredField("value");
f.setAccessible(true);
System.out.println(immutable.getValue());
f.set(immutable, Integer.MAX_VALUE);
System.out.println(immutable.getValue());
}
}
Run Code Online (Sandbox Code Playgroud)
鉴于依赖于反射的框架数量(Spring和Hibernate只有少数),我很好奇规范说明了这个场景.例如,如果我将字段更新放入synchronized块中将保证其他线程中的可见性,或者值将根据spec的最终版本缓存在寄存器中.
http://download.oracle.com/otndocs/jcp/memory_model-1.0-pfd-spec-oth-JSpec/
我们的应用程序使用了大量字典,这些字典具有不经常更改的多级查找.我们正在研究转换使用字典进行大量查找的一些关键代码,以使用替代结构 - 更快的查找,点亮内存/ gc.这让我们比较了各种可用的词典/库 -
Dictionary(System.Collections.Generics.Dictionary-SCGD) ,ImmutableDictionary,.C5.HashDictionaryFSharpMap
运行包含各种项目的以下程序 - 100,1000,10000,100000 - 表示词典在大多数范围内仍然是赢家.第一行表示集合中的项目.MS/Ticks将随机执行x查找所花费的时间(代码如下).
项目 - 100
SCGD - 0 MS - 50 Ticks
C5 - 1 MS - 1767 Ticks
Imm - 4 MS - 5951 Ticks
FS - 0 MS - 240 Ticks
项目 - 1000
SCGD - 0 MS - 230 Ticks
C5 - 0 MS - 496 Ticks
Imm - 0 MS - 1046 Ticks
FS - 1 MS - 1870 …
我想从冻结集中获取一个元素(当然,不修改它,因为frozensets是不可变的).到目前为止我找到的最佳解决方案是:
s = frozenset(['a'])
iter(s).next()
Run Code Online (Sandbox Code Playgroud)
按预期返回:
'a'
Run Code Online (Sandbox Code Playgroud)
换句话说,有没有任何方法可以从冻结集中"弹出"一个元素而不实际弹出它?
如果我想将我的视图控制器的状态表示为单个结构然后实现撤销机制,那么我如何更改结构上的一个属性,同时获取前一个状态的副本?
struct A {
let a: Int
let b: Int
init(a: Int = 2, b: Int = 3) {
self.a = a
self.b = b
}
}
let state = A()
Run Code Online (Sandbox Code Playgroud)
现在我想要一份state但是b = 4 的副本.如何在不构造新对象且必须为每个属性指定值的情况下执行此操作?
Haskell如何解决"规范化的不可变数据结构"问题?
例如,让我们考虑代表前女友/男朋友的数据结构:
data Man = Man {name ::String, exes::[Woman]}
data Woman = Woman {name :: String, exes::[Man]}
Run Code Online (Sandbox Code Playgroud)
如果一个女人改变她的名字并且她和13个男人在一起会怎么样?然后所有13个人都应该"更新"(在Haskell意义上)?需要某种规范化来避免这些"更新".
这是一个非常简单的例子,但想象一个具有20个实体的模型,以及它们之间的任意关系,那么该做什么呢?
在不可变语言中表示复杂的规范化数据的推荐方法是什么?
例如,可以在此处找到Scala解决方案(请参阅下面的代码),它使用引用.在Haskell可以做些什么
class RefTo[V](val target: ModelRO[V], val updated: V => AnyRef) {
def apply() = target()
}
Run Code Online (Sandbox Code Playgroud)
我想知道,如果像上面的那些(在Scala中)更通用的解决方案在Haskell中不起作用或者它们不是必需的吗?如果它们不起作用,为什么不呢?我试图搜索在Haskell中执行此操作的库,但它们似乎不存在.
换句话说,如果我想在Haskell中建模规范化的SQL数据库(例如与酸状态一起使用),是否有一种描述外键的通用方法?一般来说,我的意思是,不要按照以下评论中chepner的建议手工编码ID.
编辑:
换句话说,是否存在一个库(用于Haskell或Scala)在内存中实现SQL /关系数据库(可能还使用事件源来实现持久性),这样数据库是不可变的和大多数SQL操作(查询/连接/插入/删除/等.)是否已实现并且是类型安全的?如果没有这样的图书馆,为什么不呢?这似乎是个不错的主意.我该如何创建这样的库?
编辑2:
一些相关链接:
haskell scala normalization immutability database-normalization
我希望有这样的不可变Java对象(强烈简化):
class Immutable {
protected String name;
public Immutable(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Run Code Online (Sandbox Code Playgroud)
在某些情况下,对象不仅应该是可读的而且是可变的,因此我可以通过继承添加可变性:
public class Mutable extends Immutable {
public Mutable(String name) {
super(name);
}
public void setName(String name) {
super.name = name;
}
}
Run Code Online (Sandbox Code Playgroud)
虽然这在技术上很好,我想知道它是否符合OOP和继承,mutable也是类型不可变的.我想避免OOP犯罪抛出UnsupportedOperationException不可变对象,就像Java集合API那样.
你怎么看?还有其他想法吗?
众所周知,String在java中是不可变的.但是,可以通过获取Field并设置访问级别来使用反射来更改它.(我知道这是未经修改的,我不打算这样做,这个问题纯粹是理论上的).
我的问题:假设我知道我在做什么(并根据需要修改所有字段),程序是否正常运行?或者jvm是否进行了一些依赖于String不可变的优化?我会遭受性能损失吗?如果是这样,它会做出什么假设?该计划会出现什么问题
ps String只是一个例子,除了示例之外,我实际上对一般答案感兴趣.
谢谢!
immutability ×10
java ×3
jvm ×2
mutable ×2
oop ×2
scala ×2
set ×2
.net ×1
caliper ×1
comparison ×1
concurrency ×1
dictionary ×1
f# ×1
guava ×1
haskell ×1
inheritance ×1
iterator ×1
performance ×1
python ×1
reflection ×1
swift ×1