标签: immutability

功能编程:不变性等

我最近问了一个关于函数式编程的问题,并收到了(好的!)答案,这些答案提出了更多问题(有时似乎是学习的情况).以下是几个例子:

  1. 一个答案提到了不可变数据结构的优点:每个线程都可以拥有自己的副本.现在,对我来说,这听起来更像是一个版本控制系统(使用类比),而不是锁定某人已经签出的代码,以便其他人无法修改,每个人都可以查看自己的副本.听起来不错.但是,在VCS中,您有"合并"更改的概念,如果两个人更改了相同的内容.似乎这个问题肯定会出现在多线程场景中......那么当线程看到最新数据时,如何完成"合并"呢?

  2. 这个答案讨论了在对象的循环中执行操作的情况,以及如何每次使用新对象而不是更新旧对象.但是,假设bankAccount正在非循环场景中进行更新 - 例如GUI银行系统.操作员单击"更改利率"按钮,该按钮将触发一个事件(例如,在C#中)执行类似操作bankAccount.InterestRate = newRateFromUser.我觉得我在这里很密集,但希望我的例子是有意义的:必须有某种方式来更新对象,对吧?其他一些事情可能取决于新数据.

无论如何,如果你能帮助我了解范式转变,我会很感激.我记得我的大脑经过类似的"愚蠢阶段",在学习OOP后,采用简单的程序性命令式编码方法.

language-agnostic concurrency functional-programming immutability

12
推荐指数
2
解决办法
3457
查看次数

如何在不重复代码的情况下编辑WPF中的不可变对象?

我们的域模型中有许多不可变值对象,其中一个例子是位置,由纬度,经度和高度定义.

/// <remarks>When I grow up I want to be an F# record.</remarks>
public class Position
{
    public double Latitude
    {
        get;
        private set;
    }

    // snip

    public Position(double latitude, double longitude, double height)
    {
        Latitude = latitude;
        // snip
    }
}
Run Code Online (Sandbox Code Playgroud)

允许编辑位置的显而易见的方法是构建具有getter setter 的ViewModel ,以及提取经验证的不可变位置实例的ToPosition()方法.虽然这个解决方案没问题,但它会产生大量重复的代码,尤其是XAML.

有问题的值对象包含三到五个属性,这些属性通常是X,Y,Z和一些辅助内容的变体.鉴于此,我考虑创建三个ViewModel来处理各种可能性,其中每个ViewModel需要公开每个属性的值的属性以及为每个标签显示的描述(例如"Latitude").

更进一步,似乎我可以将它简化为一个可以处理N个属性并使用反射挂钩所有内容的一般ViewModel.像属性网格,但对于不可变对象.属性网格的一个问题是我希望能够更改外观,以便我可以使用标签和文本框,例如:

Latitude:   [      32 ]  <- TextBox
Longitude:  [     115 ]
Height:     [      12 ]
Run Code Online (Sandbox Code Playgroud)

或者将它放在DataGrid中,例如:

Latitude  |  Longitude  |  Height
      32           115         12
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:

你能想出一个解决这个问题的优雅方法吗?有没有这样做的图书馆或关于类似的东西的文章?

我主要是在寻找:

  • 代码重复最小化
  • 易于添加新的值对象类型
  • 可以通过某种验证来扩展

wpf immutability

12
推荐指数
2
解决办法
1379
查看次数

自动生成不可变类和匹配构建器类

存在哪些工具/库将采用结构并自动生成不可变包装器以及用于逐步构建新实例的"构建器"类?

输入示例:

struct Foo
{
    public int apples;
    public int oranges;
    public Foo Clone() {return (Foo) base.MemberwiseClone();}
}
Run Code Online (Sandbox Code Playgroud)

示例输出:

public class ImmutableFoo // could probably be a struct
{
    private Foo snapshot;
    internal ImmutableFoo(Foo value) { this.snapshot = value; }
    public FooBuilder Builder() { return new FooBuilder(snapshot); }
    public int Apples { get { return snapshot.apples; } }
    public int Oranges { get { return snapshot.oranges; } }
}

public class FooBuilder
{
    private Foo state;

    public int Apples { …
Run Code Online (Sandbox Code Playgroud)

c# language-agnostic design-patterns immutability builder-pattern

12
推荐指数
1
解决办法
2550
查看次数

可变类作为不可变类的子类

我希望有这样的不可变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那样.

你怎么看?还有其他想法吗?

java oop inheritance mutable immutability

12
推荐指数
3
解决办法
3964
查看次数

使用反射更改字符串的效果

众所周知,String在java中是不可变的.但是,可以通过获取Field并设置访问级别来使用反射来更改它.(我知道这是未经修改的,我不打算这样做,这个问题纯粹是理论上的).

我的问题:假设我知道我在做什么(并根据需要修改所有字段),程序是否正常运行?或者jvm是否进行了一些依赖于String不可变的优化?我会遭受性能损失吗?如果是这样,它会做出什么假设?该计划会出现什么问题

ps String只是一个例子,除了示例之外,我实际上对一般答案感兴趣.

谢谢!

java jvm immutability

12
推荐指数
2
解决办法
4323
查看次数

什么是破坏性更新?

我看到许多与函数式编程相关的主题都提到了破坏性更新.我知道它与变异类似,所以我理解更新部分.但破坏性的部分是什么?或者我只是过度思考它?

functional-programming immutability

12
推荐指数
1
解决办法
3997
查看次数

PHP:不可变的公共成员字段

我需要创建一个不可变的类,它只是一个成员字段容器.我希望它的字段在其构造函数中实例化一次(值应作为构造函数的参数给出).我希望这些字段是公开的但不可变的.我可以final在每个字段之前使用关键字用Java完成它.它是如何在PHP中完成的?

php immutability

12
推荐指数
1
解决办法
4058
查看次数

使用Jackson进行不可变/多态POJO < - > JSON序列化

我正在尝试使用Jackson 2.1.4将不可变的POJO与JSON序列化,而不必编写自定义序列化程序并尽可能少注释.我还想避免为了满足Jackson库而添加不必要的getter或默认构造函数.

我现在卡在异常上:

JsonMappingException:找不到类型[simple type,class Circle]的合适构造函数:无法从JSON对象实例化(需要添加/启用类型信息?)

代码:

public abstract class Shape {}


public class Circle extends Shape {
  public final int radius; // Immutable - no getter needed

  public Circle(int radius) {
    this.radius = radius;
  }
}


public class Rectangle extends Shape {
  public final int w; // Immutable - no getter needed
  public final int h; // Immutable - no getter needed

  public Rectangle(int w, int h) {
    this.w = w;
    this.h = h;
  }
}
Run Code Online (Sandbox Code Playgroud)

测试代码:

ObjectMapper mapper …
Run Code Online (Sandbox Code Playgroud)

java inheritance json immutability jackson

12
推荐指数
1
解决办法
6326
查看次数

C#中不可变的局部"变量"

我是C#的新手(主要是C++程序员,Java是强大的第二个,而其他一些我不经常使用); 我正在使用C#和Unity,但我有一个似乎与C#相关的问题而不是Unity.

我一直在朝着功能风格的编程方向发展,即代替

// C++
int someFunction(int a) {
    int someCalculatedValue = a * a;
    someCalculatedValue /= 2;
    return someCalculatedValue * 3;
}
Run Code Online (Sandbox Code Playgroud)

我会做这样的事情

// Again C++
int someFunction(int a) {
    const int inputSquared = a * a;
    const int inputSquaredHalved = inputSquared / 2;
    return inputSquaredHalved * 3;
}
Run Code Online (Sandbox Code Playgroud)

现在,我想在C#中做到这一点,但我已经尝试过了

// C#
const float maxGrowth = GrowthRate * Time.deltaTime;
Run Code Online (Sandbox Code Playgroud)

但Mono抱怨说,maxGrowth没有被赋予"常量值" - 所以我假设C#的const关键字实际上相当于来自C++ 11的'constexpr'?

如果是这样,有没有办法在C#中做我想做的事情?最好不要调用一些容器类(除非编译器擅长提高效率?).

我假设从我所读到的内容中,C#在语言方面比C++更接近于Java; 不可变类而不是const-member函数?

c# immutability

12
推荐指数
2
解决办法
3477
查看次数

跨API传递不可变集合的最佳模式是什么

在不可变性之前,IEnumerable是许多API中的首选接口,因为它具有API对传递对象的实际类型不敏感的优点.

public void DoSomeEnumerationsWithACollection(IEnumerable<Thing> collectionOfThings)
{ 
   foreach (var thing in collectionOfThings) doSomethingWith(thing);
   foreach (var thing in collectionOfThings) doSomethingElseWith(thing);
}
Run Code Online (Sandbox Code Playgroud)

当然,至少有两个缺点:

  1. API背后的代码不能依赖collectionOfThings的不变性,可能会遇到"集合修改"异常或遇到其他其他微妙问题.

  2. 我们不知道collectionOfThings是真实集合还是简单的延迟查询.如果我们假设它是一个真正的集合,那么我们就不会通过运行多个枚举来降低性能.如果我们假设它是一个延迟查询并且它实际上是一个真实的集合,那么将其转换为本地列表或其他冻结集合会产生不必要的成本,尽管它确实有助于保护我们免受第一个问题的影响(执行"ToList"操作时仍存在竞争条件).显然,我们可以编写少量代码来检查这一点,并尝试做"正确的事情",但这是令人讨厌的额外混乱.

我必须承认,除了使用命名约定之外,我从未找到过令人满意的模式来解决这个问题.尽管存在缺点,但是实用的方法似乎是IEnumerable是传递集合的最低摩擦方法.

现在,随着不可变的收藏,情况得到了很大改善......

public void DoSomeEnumerationsWithACollection(ImmutableList<Thing> collectionOfThings)
{ 
Run Code Online (Sandbox Code Playgroud)

不再存在收集修改的风险,并且对多个枚举的性能影响没有任何歧义.

但是,我们显然失去了API的灵活性,因为我们现在必须传入一个ImmutableList.如果我们的客户端有其他类型的可枚举不可变集合,则必须将其复制到ImmutableList中才能被使用,即使我们想要做的只是枚举它.

理想情况下,我们可以使用类似的界面

public void DoSomeEnumerationsWithACollection(IImmutableEnumerable<Thing> collectionOfThings)
Run Code Online (Sandbox Code Playgroud)

但是,当然,除了约定之外,接口不能强制执行不可变性等语义.

使用基类可能会起作用

public void DoSomeEnumerationsWithACollection(ImmutableEnumerableBase<Thing> collectionOfThings)
Run Code Online (Sandbox Code Playgroud)

除了它被认为是创建未密封的不可变类的不良形式,以免子类引入可变性.无论如何,这还没有在BCL中完成.

或者我们可以继续在API中使用IEnumerable并使用命名约定来明确我们的代码依赖于传递的不可变集合.

所以...我的问题是在传递不可变集合时哪些模式被认为是最好的?是ImmutableList "新的IEnumerable "一旦我们开始使用不可变性,或是否有更好的办法?

更新

IReadOnlyCollection(由Yuval Itzchakov建议)是对IEnumerable的明显改进,但仍然没有完全保护消费者免受集合中不受控制的变化的影响.值得注意的是,Roslyn代码库大量使用不变性(主要通过ImmutableArray)并且在将这些传递给其他方法时似乎使用显式类型,尽管有几个位置将ImmutableList传递给接受IEnumerable的方法.

.net c# immutability immutablelist immutable-collections

12
推荐指数
2
解决办法
822
查看次数