Live data from Hacker News

Twenty five thousand dollars of funny money

rachelbythebay.com

101–110 of 175 posts

Re: Twenty five thousand dollars of funny money

#101

One of the things I really like about f# is thar you can tag even raw numbers with types. And even multiply/divide on those types. https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...

Nim as well, they even have an example[0] with currencies. [0] https://nim-lang.org/docs/manual.html#distinct-type-modeling...

One can, of course, go much further than simply distinct number types in Nim: https://github.com/ringabout/awesome-nim#science

(Unchained seems maybe the most featureful of those units packages.)

Re: Twenty five thousand dollars of funny money

#102

Earlier quoted context omitted.

You don't need "strict typing" to handle money; in the old (COBOL) days, we used BCD to represent monetary amounts with arbitrary precision. When they took away BCD, we were stuck, if we wanted to build a system that could represent a large sum correctly in both dollars and yen. COBOL was pretty good for dealing with money.

Could you expand on BCD? What made it good for multi-currency work? (a quick google did not help, managed to lead to examples of COBOL manipulating the first five letters of the alphabet ...)

Binary Coded Decimal allows for perfect representation of numbers by not restricting you to 4 or 8 bytes. It trades speed and memory efficiency for precision and simplicity.

https://en.m.wikipedia.org/wiki/Binary-coded_decimal

Re: Twenty five thousand dollars of funny money

#103
One of the first programming languages I learned was TI BASIC on the TI-89. It had an excellent units (refinement types) system: you could define an expression as a "unit" by prefixing a variable with an underscore, and it came with a bunch of built-in units. A unit expression could thereby automatically convert between types as needed, outputing the base unit.

E.g. `5_dollars + 8_cents` would output `508_cents`. There was also a conversion operator you could use to change the output unit, so `5_dollars + 8_cents→_dollars` would output `5.08_dollars`.

It even worked for more complicated derived units, so e.g. `8_m * 5_kg / (3_s * 4_s)` returns `3.333_N`.

Re: Twenty five thousand dollars of funny money

#104
post #48

Earlier quoted context omitted.

This bug could easily happen in a typed language though. function deduct(int cents) { ... } int dollars = ... deduct(dollars); You need something like (Apps) Hungarian notation [1] as a minimum - or even better, subtypes of primitives like in Go to represent units in a typesafe way. [1] https://en.m.wikipedia.org/wiki/Hungarian_notation

You should define separate types for “cents” and “dollars”. And, probably operations to convert between the types.

You can have a single type for “money” (or maybe just “us_money”) with separate cents/dollars/mills factories and accessors, and no access to a numeric value except through the accessors.

You can do similar things with other dimensions like “length”.

Or you can go whole hog, and have a single “type” for unit-aware values from which you can only successfully extract a unitless number by specifying a unit which is dimensionally compatible.

But most projects won’t do any of these because they will start out thinking they don’t need it, and by the time they realize the value they’ll think the cost of converting existing code is too high.

Re: Twenty five thousand dollars of funny money

#105

One of the things I really like about f# is thar you can tag even raw numbers with types. And even multiply/divide on those types. https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...

This is probably the one feature from F# that I truly miss in other languages.

Re: Twenty five thousand dollars of funny money

#106
post #74

Critical things come with critical stickers: Transformer boxes, Nuclear waste, Highly acidic compounds, High energy lasers, choking hazards. The oldest debate: should there be a money primitive in the type system? I mean, availability breeds use, use breeds awareness, awareness breeds or enforces proper use. A currency/money type would be a pretty clear label to ward off a whole suite of stupid bugs like the one desc…

or just units of measure a more general solution than what you're suggesting, implemented by languages like F# https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...

Wow that is a cool feature, thanks for sharing.

I think there are some other things like fixed-point rather than floating-point decimals for storing/manipulating currency. IIRC, the number 0.1 cannot be precisely represented with floating point system, but that just may be an old wives tale at this point.

Re: Twenty five thousand dollars of funny money

#107
I was working with [top 5 bank in the US] and hit the same issue with regards to their interest rates between products.

Some represented interest rates as a simple number "5%" others as a decimal "0.05" and others as basis points (500). It caused some HUGE problems internally as less clueful loan officers were plugging 0.05% interest rates into formulas for customers. The naming was just as bad. We had columns and fields called intRate, int_rate, interest_rate, and of course iRate.

I asked people if they were irate over the problem. No one laughed. :D

Re: Twenty five thousand dollars of funny money

#108
post #48

Earlier quoted context omitted.

This bug could easily happen in a typed language though. function deduct(int cents) { ... } int dollars = ... deduct(dollars); You need something like (Apps) Hungarian notation [1] as a minimum - or even better, subtypes of primitives like in Go to represent units in a typesafe way. [1] https://en.m.wikipedia.org/wiki/Hungarian_notation

I think you’re confusing expressiveness of types with static/dynamic typing (the latter are also typed!) An expressive type system would allow you to define both a cent and dollar types, s.t. assignments of those types to each other without conversion would fail. In a way, it is a way to have the computer validate apps Hungarian rather than trusting the programmer (well, it’s more, but for this argument). Go’s type s…

> The usefulness of this purpose not to be discussed here

This is a fantastic bit to tack on for divisive topics, I'm stealing it.

Re: Twenty five thousand dollars of funny money

#109
post #26

I think I like the duck typing in TypeScript more than I dislike it. But I still wish I could say “this function accepts a type called RobotName. It’s a string, but so is RobotUuid, and we don’t want that. So only accept, strictly, objects typed as RobotName.”

Way back in the 1990s I worked in a place where we had to use Ada and follow a strict style guide. The guide prohibited using raw numeric types (such as "unsigned int" or "double" in C-like languages) and required creating a new type ( https://en.wikibooks.org/wiki/Ada_Programming/Type_System#De... ) for each different quantity, such as temperature or speed. Then you couldn't assign a speed value to a temperature var…

Many C++ code bases still do this pervasively, it is a common practice to improve robustness. I don't know what it is like in Ada but C++ metaprogramming makes this not too onerous.

Re: Twenty five thousand dollars of funny money

#110

My primary codebase ingests data with a mix of seconds, milliseconds, and microseconds. We've held it at bay for a while, but it requires some mental overhead unless we've baked the unit into each variable name. We're likely to normalize on milliseconds, but at the same time, the implication of floating point arithmetic on all our μs numbers isn't ideal.

In a similar vein, in the early days of launching Relay[1] I ended up spending a couple weeks in total squashing timestamp bugs. We were integrating with a few existing systems that used epoch seconds or milliseconds for timestamps and they usually didn't have a hint in the field name to tell what it was so it was really easy to miss in code reviews.

Our problems were caused by a mix of serialization format (JSON numbers) and not always converting into the language's date/time types at the boundary (sometimes raw epoch seconds/millis were passed around layers of code and only parsed into a date for display. That created opportunities for misinterpretation at every function call.

My general rules for non-performance critical code are

1. Always Parse into a first-class date/time/duration type at the serialization boundary.

2. Always use an unambiguous format (e.g. ISO-8601) for serialization

It's not the most efficient but lets you rely on the type system for everything in your code and only deal with conversion at one place.

[1] https://relay.amazon.com/

Post reply on HN