Two user inputs that alter each other

I have a user interface with two numeric input boxes, send amount and receive amount. The values are in different currencies and are related by an exchange rate. That is, receive amount should always be send amount * exchange rate. But the user is allowed to click into either input box and modify the value, which causes the other value to be updated.

I’ve got a simple system to observe changes to either value and update the other one. I’ve had problems with infinite loops of the values updating each other because they’re floats and multiplying then dividing by the exchange rate doesn’t always create precisely the same value. So I added a simple flag to ignore updates while the updater itself is running.

But now I’m adding more functionality when the user updates an amount field, requiring other objects to listen to the fields. As a result some of those objects end up changing one of the amount fields, which sets off an infinite loop.

I’ve always felt like this is a fragile modelling of the problem, but I haven’t thought of anything better. Is there any established pattern or approach to modelling two values that update each other?

The right way to implement state and state change notifications is epitomized by the following setter method pseudocode:

method setValue( T newValue )
{
    if( newValue equals existingValue )
        return;
    existingValue = newValue;
    issue state change notification;
}

This is known to work, and to work perfectly. No infinite loops, no oscillations, no unnecessary notifications, no problems whatsoever.

Until one day someone decides to use floats.

Your problem is not with the very well established concept of state change notifications and the observer pattern, your problem is with the fact that you have been using a crappy data type for the job.

You tried to overcome the malfunctions caused by the imprecision inherent in floats with an approach which, although not outright wrong, was not really the correct approach for the problem at hand: you added a flag to ignore updates while the updater itself is running.

So, here are some approaches for solving your problem directly, instead of letting it be and trying to work around it:

  1. Use proper equality comparisons for your floats: if( abs( float1 - float2 ) < epsilon ) where epsilon is a very small number like 0.00000001, depending on the desired precision. For more information, see this: What’s wrong with using == to compare floats in Java?

  2. Use a “decimal” or “BigDecimal” data type instead of float. If you are dealing with currency values, you definitely should be doing this. For more information, see this: Why not use Double or Float to represent currency?

There’s a nice video from Apple’s WWDC about this subject. Solution is simple:

Stored somewhere is the truth. The truth is not a number, it is a pair (number, currency). If a user enters a number into a Yen field, the truth is changed to X Yen. When a dollar field is notified, it doesn’t change the truth to dollars. It displays the amount as best as it can, but it doesn’t change the truth doing that. Only when the user enters a number, the truth is changed.

When the question was asked, there was the assumption that there are two truths, related by a formula, and that is where the trouble starts. One truth, not two.

1

Add an argument called sender which can be chained together as events are raised. As a first step check to see if if the current object is on the chain, if so, just mark as handled so no updates occur.

Example

Button1 initiates change.

Sender: Button1

Button2 intercepts, first thing it does is check if it’s already on the sender chain. In this case it is not, so it does an update, adding another sender on the chain (Button1, Button2) and raises an event that it has changed. Button1 intercepts, inspects chain, Button1 and Button2 are on the chain, so it shouldn’t do an update and thus no more events will be raised.

This way the UI doesn’t end up chasing its tail.

The two input boxes are two views onto the same value. If one box is changed, the other is changed as well. Therefore, there should be no separate “on change” event to subscribe to. The two immediate event handlers just emit one common event that takes note of which box was edited. Pseudocode:

class ConvertFromTo(from: Input, to: Input) {
  val on-change = new Observable[ChangeEvent]()
  from.on-change.add(e => on-change.emit(new ChangeEvent(this, Direction.From, e.value))
  to.on-change.add(e => on-change.emit(new ChangeEvent(this, Direction.To, e.value))
}

This allows external listeners to subscribe to the combined ConvertFromTo.on-change observable. You can use this abstraction layer to weed out events that didn’t actually change the conversion value. If some component needs to be notified on changes to the displayed value, the can still subscribe directly to the change event of that input field.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật