Сообщение Re[2]: Observable calculations от 17.11.2019 16:34
Изменено 18.11.2019 7:44 igor-booch
Re[2]: Observable calculations
SS>Замечания по английскому
SS>1. В реактивном программировании обычно вычисленные значения называются computed values. В mobx (кстати, JS библеотека для reactive programming) это также называется derived value. Calculation обычно вязанно с числами, что сбивает с толку.
Спасибо за замечание. Скорей всего буду переименовать.
SS>2. Исполозование ing в именах режет слух, так как это предполагает что-то происходит прямо сейчас. Calculating<> — что-то считается сейчас. Подходящее имя для состояния, но не для сущности. Некоторые слова просто не существуют, типа Distincting, Excepting.
Окончанием ing я хотел подчеркнуть непрерывность и продолжительность. То есть Select — это выбрать. Выбрали и действие на этом закончено. У меня выборка происходит непрерывно, в том числе сейчас. Для сущности можно считать Selecting — герундием. Да, Distincting, Excepting отсутсвуют в английском, но можно рассматривать это как сокращения или словообразованием. Я не знаю как назвать покороче сохранив суть.
SS>3. Complicity -> Complexity?
Да, спасибо
SS>Дизайн:
SS>Заявления про функциоанальный стиль не подтверждаются примерами. Например discountedPriceExpression не является чистой функцией. Правильнее было бы требовать от пользователя функцию Func<Order, decimal> и вызывать её когда нужно.
Можно и с Func<Order, decimal>. Тогда код будет таким:
Вместо Calculating, используем Using.
SS>Функциоанальный стиль так же предполагает работу с, или как минимум хорошую поддержку, immutable data structures. Было бы хорошо, если бы можно было сделать Order immutable, иметь для него какой-то observable контейнер, применить к нему Func<Order, decimal>, и получить другой observable контейнер.
Вся идея как раз и заключается чтобы следить за изменениями в изменяемых структурах данных. OC можно рассматривать как мост между императивным и фукциональным подходами.
SS>Производительность:
SS>Хорошо бы указать модель change propagation. Как обрабатываются ромбы в графе зависимостей: вершина будут пересчитана онин раз или несколько раз? Пересчитываются ли те узлы в графе, которые никто не читает? Строит ли фреймворк DAG обновлений, чтобы обрабатывать ситуацию https://en.wikipedia.org/wiki/File:Reactive_programming_glitches.svg (см. wiki раздел "glitches"), или глюки — забота пользователя фреймворка?
Делаем эксперимент
На выходе
observableTimer.Seconds меняли 2 раза, но событие изменения g пришло 4 раза,
потому что при одном изменении observableTimer.Seconds меняется, первое: он сам, второе: меняется t.
В принципе изменения на одно и тоже значение можно подавить в клиентском коде, либо можно создать ещё один тип вычислений: DistinctiveCalculating с возможностью передавать в него EqualityComparer. Наверное реализую в будующем, это не сложно.
Но вернёмся к примеру. Здесь мы получаем везде true так как событие PropertyChanged от observableTimer первым обрабатывается в t, потом уже в g. В C# порядок вызова обработчиков совпадает с порядком подписки. Но это деталь реализации и полагаться на это в общем случае нельзя. Это проблема для OC. Если порядок обработки событий изменится то мы можем получить:
Отступление: OC не застрахован временных невалидных состояний, так как одно изменение коллекции источника может породить несколько изменений вычисляемой коллекции. Например, если в коллекции источнике для Ordering произошёл Replace, то в Ordering сначала происходит Replace, а потом Move. Очевидно, что после Replace и до Move, коллекция Ordering будет упорядочена неправильно, но Move восстанавит порядок. После Replace свойство Ordering.Consistent станет = false. После Move Ordering.Consistent станет = true; Это модель временной инконсистентности.
ThenOrdering вообще может отвалиться, если одно и тоже свойство, одного и того же объекта используется в ключе для Ordering и для ThenOrdering и порядок вызова обработчиков будет отличен от порядка подписки на событие изменения свойства. Эту проблему с ThenOrdering пока не решил, но случай очень экзотитческий.
SS>1. В реактивном программировании обычно вычисленные значения называются computed values. В mobx (кстати, JS библеотека для reactive programming) это также называется derived value. Calculation обычно вязанно с числами, что сбивает с толку.
Спасибо за замечание. Скорей всего буду переименовать.
SS>2. Исполозование ing в именах режет слух, так как это предполагает что-то происходит прямо сейчас. Calculating<> — что-то считается сейчас. Подходящее имя для состояния, но не для сущности. Некоторые слова просто не существуют, типа Distincting, Excepting.
Окончанием ing я хотел подчеркнуть непрерывность и продолжительность. То есть Select — это выбрать. Выбрали и действие на этом закончено. У меня выборка происходит непрерывно, в том числе сейчас. Для сущности можно считать Selecting — герундием. Да, Distincting, Excepting отсутсвуют в английском, но можно рассматривать это как сокращения или словообразованием. Я не знаю как назвать покороче сохранив суть.
SS>3. Complicity -> Complexity?
Да, спасибо
SS>Дизайн:
SS>Заявления про функциоанальный стиль не подтверждаются примерами. Например discountedPriceExpression не является чистой функцией. Правильнее было бы требовать от пользователя функцию Func<Order, decimal> и вызывать её когда нужно.
Можно и с Func<Order, decimal>. Тогда код будет таким:
Expression<Func<Order, decimal>> discountedPriceExpression =
o => o.Price - o.Price * o.Discount / 100;
//********************************************
// We start using ObservableCalculations here!
Calculating<decimal> discountedPriceCalculating =
order.Using(discountedPriceExpression);
Вместо Calculating, используем Using.
SS>Функциоанальный стиль так же предполагает работу с, или как минимум хорошую поддержку, immutable data structures. Было бы хорошо, если бы можно было сделать Order immutable, иметь для него какой-то observable контейнер, применить к нему Func<Order, decimal>, и получить другой observable контейнер.
Вся идея как раз и заключается чтобы следить за изменениями в изменяемых структурах данных. OC можно рассматривать как мост между императивным и фукциональным подходами.
SS>Производительность:
SS>Хорошо бы указать модель change propagation. Как обрабатываются ромбы в графе зависимостей: вершина будут пересчитана онин раз или несколько раз? Пересчитываются ли те узлы в графе, которые никто не читает? Строит ли фреймворк DAG обновлений, чтобы обрабатывать ситуацию https://en.wikipedia.org/wiki/File:Reactive_programming_glitches.svg (см. wiki раздел "glitches"), или глюки — забота пользователя фреймворка?
Делаем эксперимент
using System;
using System.ComponentModel;
using IBCode.ObservableCalculations;
namespace ObservableCalculationsExamples
{
public class ObservableTimer : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _seconds;
public int Seconds
{
get => _seconds;
set
{
_seconds = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Seconds)));
}
}
}
class Program
{
static void Main(string[] args)
{
ObservableTimer observableTimer = new ObservableTimer();
Calculating<int> t = Expr.Is(() => observableTimer.Seconds + 1).Calculating();
Calculating<bool> g = Expr.Is(() => t.Value > observableTimer.Seconds).Calculating();
g.PropertyChanged += (sender, eventArgs) =>
{
if (eventArgs.PropertyName == nameof(Calculating<bool>.Value))
Console.WriteLine(g.Value);
};
observableTimer.Seconds++;
observableTimer.Seconds++;
Console.ReadLine();
}
}
}
На выходе
True
True
True
True
observableTimer.Seconds меняли 2 раза, но событие изменения g пришло 4 раза,
потому что при одном изменении observableTimer.Seconds меняется, первое: он сам, второе: меняется t.
В принципе изменения на одно и тоже значение можно подавить в клиентском коде, либо можно создать ещё один тип вычислений: DistinctiveCalculating с возможностью передавать в него EqualityComparer. Наверное реализую в будующем, это не сложно.
Но вернёмся к примеру. Здесь мы получаем везде true так как событие PropertyChanged от observableTimer первым обрабатывается в t, потом уже в g. В C# порядок вызова обработчиков совпадает с порядком подписки. Но это деталь реализации и полагаться на это в общем случае нельзя. Это проблема для OC. Если порядок обработки событий изменится то мы можем получить:
Но последнее изменение будет в любом случае True. То есть возможно временное невалидное состояние, которое в конечном итоге переходит в валидное.False
True
False
True
Отступление: OC не застрахован временных невалидных состояний, так как одно изменение коллекции источника может породить несколько изменений вычисляемой коллекции. Например, если в коллекции источнике для Ordering произошёл Replace, то в Ordering сначала происходит Replace, а потом Move. Очевидно, что после Replace и до Move, коллекция Ordering будет упорядочена неправильно, но Move восстанавит порядок. После Replace свойство Ordering.Consistent станет = false. После Move Ordering.Consistent станет = true; Это модель временной инконсистентности.
ThenOrdering вообще может отвалиться, если одно и тоже свойство, одного и того же объекта используется в ключе для Ordering и для ThenOrdering и порядок вызова обработчиков будет отличен от порядка подписки на событие изменения свойства. Эту проблему с ThenOrdering пока не решил, но случай очень экзотитческий.
Re[2]: Observable calculations
SS>Замечания по английскому
SS>1. В реактивном программировании обычно вычисленные значения называются computed values. В mobx (кстати, JS библеотека для reactive programming) это также называется derived value. Calculation обычно вязанно с числами, что сбивает с толку.
Спасибо за замечание. Скорей всего буду переименовать.
SS>2. Исполозование ing в именах режет слух, так как это предполагает что-то происходит прямо сейчас. Calculating<> — что-то считается сейчас. Подходящее имя для состояния, но не для сущности. Некоторые слова просто не существуют, типа Distincting, Excepting.
Окончанием ing я хотел подчеркнуть непрерывность и продолжительность. То есть Select — это выбрать. Выбрали и действие на этом закончено. У меня выборка происходит непрерывно, в том числе сейчас. Для сущности можно считать Selecting — герундием. Да, Distincting, Excepting отсутсвуют в английском, но можно рассматривать это как сокращения или словообразованием. Я не знаю как назвать коротко сохранив суть.
SS>3. Complicity -> Complexity?
Да, спасибо
SS>Дизайн:
SS>Заявления про функциоанальный стиль не подтверждаются примерами. Например discountedPriceExpression не является чистой функцией. Правильнее было бы требовать от пользователя функцию Func<Order, decimal> и вызывать её когда нужно.
Можно и с Func<Order, decimal>. Тогда код будет таким:
Вместо Calculating, используем Using.
SS>Функциоанальный стиль так же предполагает работу с, или как минимум хорошую поддержку, immutable data structures. Было бы хорошо, если бы можно было сделать Order immutable, иметь для него какой-то observable контейнер, применить к нему Func<Order, decimal>, и получить другой observable контейнер.
Вся идея как раз и заключается чтобы следить за изменениями в изменяемых структурах данных. OC можно рассматривать как мост между императивным и функциональным подходами.
SS>Производительность:
SS>Как обрабатываются ромбы в графе зависимостей: вершина будут пересчитана онин раз или несколько раз? Пересчитываются ли те узлы в графе, которые никто не читает? Строит ли фреймворк DAG обновлений, чтобы обрабатывать ситуацию https://en.wikipedia.org/wiki/File:Reactive_programming_glitches.svg (см. wiki раздел "glitches"), или глюки — забота пользователя фреймворка?
Делаем эксперимент
На выходе
observableTimer.Seconds меняли 2 раза, но событие изменения g пришло 4 раза,
потому что при одном изменении observableTimer.Seconds меняется, первое: он сам, второе: меняется t.
В принципе изменения на одно и тоже значение можно подавить в клиентском коде, либо можно создать ещё один тип вычислений: DistinctiveCalculating с возможностью передавать в него EqualityComparer. Наверное реализую в будующем, это не сложно.
Но вернёмся к примеру. Здесь мы получаем везде true так как событие PropertyChanged от observableTimer первым обрабатывается в t, потом уже в g. В C# порядок вызова обработчиков совпадает с порядком подписки. Но это деталь реализации и полагаться на это в общем случае нельзя. Это проблема для OC. Если порядок обработки событий изменится то мы можем получить:
Отступление: OC не застрахован временных невалидных состояний, так как одно изменение коллекции источника может породить несколько изменений вычисляемой коллекции. Например, если в коллекции источнике для Ordering произошёл Replace, то в Ordering сначала происходит Replace, а потом Move. Очевидно, что после Replace и до Move, коллекция Ordering будет упорядочена неправильно, но Move восстанавит порядок. После Replace свойство Ordering.Consistent станет = false. После Move Ordering.Consistent станет = true; Это модель временной инконсистентности.
ThenOrdering вообще может отвалиться, если одно и тоже свойство, одного и того же объекта используется в ключе для Ordering и для ThenOrdering и порядок вызова обработчиков будет отличен от порядка подписки на событие изменения свойства. Эту проблему с ThenOrdering пока не решил, но случай очень экзотитческий.
SS>Хорошо бы указать модель change propagation.
Модель change propagation push. Спасибо выжное замечание для документации.
SS>1. В реактивном программировании обычно вычисленные значения называются computed values. В mobx (кстати, JS библеотека для reactive programming) это также называется derived value. Calculation обычно вязанно с числами, что сбивает с толку.
Спасибо за замечание. Скорей всего буду переименовать.
SS>2. Исполозование ing в именах режет слух, так как это предполагает что-то происходит прямо сейчас. Calculating<> — что-то считается сейчас. Подходящее имя для состояния, но не для сущности. Некоторые слова просто не существуют, типа Distincting, Excepting.
Окончанием ing я хотел подчеркнуть непрерывность и продолжительность. То есть Select — это выбрать. Выбрали и действие на этом закончено. У меня выборка происходит непрерывно, в том числе сейчас. Для сущности можно считать Selecting — герундием. Да, Distincting, Excepting отсутсвуют в английском, но можно рассматривать это как сокращения или словообразованием. Я не знаю как назвать коротко сохранив суть.
SS>3. Complicity -> Complexity?
Да, спасибо
SS>Дизайн:
SS>Заявления про функциоанальный стиль не подтверждаются примерами. Например discountedPriceExpression не является чистой функцией. Правильнее было бы требовать от пользователя функцию Func<Order, decimal> и вызывать её когда нужно.
Можно и с Func<Order, decimal>. Тогда код будет таким:
Expression<Func<Order, decimal>> discountedPriceExpression =
o => o.Price - o.Price * o.Discount / 100;
//********************************************
// We start using ObservableCalculations here!
Calculating<decimal> discountedPriceCalculating =
order.Using(discountedPriceExpression);
Вместо Calculating, используем Using.
SS>Функциоанальный стиль так же предполагает работу с, или как минимум хорошую поддержку, immutable data structures. Было бы хорошо, если бы можно было сделать Order immutable, иметь для него какой-то observable контейнер, применить к нему Func<Order, decimal>, и получить другой observable контейнер.
Вся идея как раз и заключается чтобы следить за изменениями в изменяемых структурах данных. OC можно рассматривать как мост между императивным и функциональным подходами.
SS>Производительность:
SS>Как обрабатываются ромбы в графе зависимостей: вершина будут пересчитана онин раз или несколько раз? Пересчитываются ли те узлы в графе, которые никто не читает? Строит ли фреймворк DAG обновлений, чтобы обрабатывать ситуацию https://en.wikipedia.org/wiki/File:Reactive_programming_glitches.svg (см. wiki раздел "glitches"), или глюки — забота пользователя фреймворка?
Делаем эксперимент
using System;
using System.ComponentModel;
using IBCode.ObservableCalculations;
namespace ObservableCalculationsExamples
{
public class ObservableTimer : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _seconds;
public int Seconds
{
get => _seconds;
set
{
_seconds = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Seconds)));
}
}
}
class Program
{
static void Main(string[] args)
{
ObservableTimer observableTimer = new ObservableTimer();
Calculating<int> t = Expr.Is(() => observableTimer.Seconds + 1).Calculating();
Calculating<bool> g = Expr.Is(() => t.Value > observableTimer.Seconds).Calculating();
g.PropertyChanged += (sender, eventArgs) =>
{
if (eventArgs.PropertyName == nameof(Calculating<bool>.Value))
Console.WriteLine(g.Value);
};
observableTimer.Seconds++;
observableTimer.Seconds++;
Console.ReadLine();
}
}
}
На выходе
True
True
True
True
observableTimer.Seconds меняли 2 раза, но событие изменения g пришло 4 раза,
потому что при одном изменении observableTimer.Seconds меняется, первое: он сам, второе: меняется t.
В принципе изменения на одно и тоже значение можно подавить в клиентском коде, либо можно создать ещё один тип вычислений: DistinctiveCalculating с возможностью передавать в него EqualityComparer. Наверное реализую в будующем, это не сложно.
Но вернёмся к примеру. Здесь мы получаем везде true так как событие PropertyChanged от observableTimer первым обрабатывается в t, потом уже в g. В C# порядок вызова обработчиков совпадает с порядком подписки. Но это деталь реализации и полагаться на это в общем случае нельзя. Это проблема для OC. Если порядок обработки событий изменится то мы можем получить:
Но последнее изменение будет в любом случае True. То есть возможно временное невалидное состояние, которое в конечном итоге переходит в валидное.False
True
False
True
Отступление: OC не застрахован временных невалидных состояний, так как одно изменение коллекции источника может породить несколько изменений вычисляемой коллекции. Например, если в коллекции источнике для Ordering произошёл Replace, то в Ordering сначала происходит Replace, а потом Move. Очевидно, что после Replace и до Move, коллекция Ordering будет упорядочена неправильно, но Move восстанавит порядок. После Replace свойство Ordering.Consistent станет = false. После Move Ordering.Consistent станет = true; Это модель временной инконсистентности.
ThenOrdering вообще может отвалиться, если одно и тоже свойство, одного и того же объекта используется в ключе для Ordering и для ThenOrdering и порядок вызова обработчиков будет отличен от порядка подписки на событие изменения свойства. Эту проблему с ThenOrdering пока не решил, но случай очень экзотитческий.
SS>Хорошо бы указать модель change propagation.
Модель change propagation push. Спасибо выжное замечание для документации.