News for hackers. Stuff that matters.

idubrov

It's an interesting topic I've spent quite a bit of time in the past...

Extensions are interesting: if you look at them long enough and consider profiling (and slicing with it), profiled extensions look pretty much like a regular data types. For example, http://hl7.org/fhir/R4B/extension-goal-acceptance.html, is nothing more than a structure with three fields in it (even though internally it's a mess of extensions).

A haven't looked at your client libraries, but one idea would be to generate "type-safe" interfaces to extensions. Maybe, something like "pack" / "unpack" of an extension? Not sure how much could be done in TypeScript world, in the past I've worked with the stack where these conversions could be integrated with the generated types themselves.

The example above would be something along the lines of "goal.extension(Acceptance)" (where "Acceptance" is generated from the StructureDefinition of an extension something something) returning structure of "{ individual: Reference; status?: code; priority?: CodeableConcept; }".

Re:Carbon offsetting is just another form of greenwashing on Monday August 08, 2022 @04:16PM (#32390483)
Wiring 240V is (typically) not an issue, as it is standard (in the US) to get 240V from the transformer to the house. The devil is in the details: what current would you wire it for, what receptacle are you going to use and what are you going to plug there.
Re:Carbon offsetting is just another form of greenwashing on Monday August 08, 2022 @10:59AM (#32386237)
Yeah, it shows that I have zero knowledge about commercial appliances. I guess, I wouldn't be surprised if they routinely use 20A plugs / receptacles. Would make sense. Maybe, hospital equipment, too?
Re:Carbon offsetting is just another form of greenwashing on Monday August 08, 2022 @09:47AM (#32385312)
The problem with 240V is that there are few NEMA standards used is USA (although , they look bulky and are kind of unsafe around the kids.

Which is not a problem for dedicated circuits (you could wire receptacle just for this specific dryer / hot tub / RV / whatever, plug it and never remove), but would be a bigger problem if 240V is shared between appliances.

I think, NEMA 6-15 / NEMA 6-20 would be the best (they look very similar to standard 120V outlets; they have tamper resistance; 15A or even 20A should be plenty enough), but nobody wires them.

Also, there are other minor differences like:

1. 50Hz in Europe vs 60Hz in USA. 2. The voltage between ground and "power" lines would be different. In Europe it would be 240v between line and ground and 0V between neutral in ground, in USA it would be 120V between ground and both power connectors, due to how 240V is typically delivered to single-family homes in USA (split phase). Should not make much difference (you are not supposed to have any current to ground anyway, and any short-circuit should trigger the circuit breaker), but maybe it will affect safety somehow? 3. Seems like in some cases in USA you can get 208V instead of 240V (and Europe is nominally 230V).

Re:Carbon offsetting is just another form of greenwashing on Monday August 08, 2022 @09:34AM (#32385180)
Right, there are code compliant solutions. I was just musing over an idea of having 240V "everywhere" (including inside the house in every room, having 240V for special needs is, of course, a solved problem).

14-50R is not what I would use in that case, they are bulky, unsightly and don't offer tamper resistance.

6-20R / 6-15R have variants that are tamper resistant, and they look like regular outlets.

"20A should be enough for everything".

We used to have 2.5-3kW kettles before we moved to US, which would require 20-25A (although, I don't think the math is that simple -- circuit breakers don't trip on "exactly 20A").

Also, the issue with 20A receptacles is that, again, I have never seen 20A plugs (NEMA 5-20P) on appliances (it has neutral connector "flat" rather than vertical). Which is understandable, why make them if nobody has 20A receptacles anyway. There is a requirement to have two 20A branches in a kitchen, but commonly they are wired to 15A receptacles.

Re:Carbon offsetting is just another form of greenwashing on Monday August 08, 2022 @12:13AM (#32382336)
(everything below assumes US and NEC / local electrical codes)

I don't think code prohibits it, but in my (not very educated) opinion, you might get into some gray territory if you try install them everywhere.

There are some safety related provisions which are mandatory for regular 120V (GFCI and/or AFCI), but I don't think they are required for 240V circuits. Building inspectors might have questions if you install these outlets everywhere. Although, again, I don't remember any limitation of where you can have them.

Another issue is the type of the receptacle. Apparently, Leviton makes receptacle that might be allowed in US and is combination of regular 120V plus European style 240V. However, it is only limited to 2.5A, which is very little (I think, this receptacle is primarily designed for hotels / shared spaces where you only want to charge your devices). Also, I don't think it has ground for 240V.

Probably, the best would be to use US 15A/20A receptacles (NEMA 6-15 / NEMA 6-20), which look very similar to the regular 120V ones (the difference is blades are horizontal).

However, I've never seen any actual plug using them (even though I did install these 240V in my garage, expecting some 240V equipment). But you can rewire plugs on your "imported" equipment / appliances.

There are also some interesting differences of the supply: in US it is typically split phase 120V+120V=240V, but sometimes (according to the internet) it could be 3 phase 120V with 208V between phases; in some parts of the world, it would be 3 phase 230V with 400V between the phases. This probably would cause some differences in how grounding works, might affect safety.

But yeah, generally, 240V should not be a problem. Power-hungry equipment (water heater, range, electrical dryer, EV chargers) -- they all typically use 240V already.

Re:Microsoft YARP on Tuesday February 22, 2022 @01:09PM (#30431246)
Re:Leaded fuel reduced IQ of children born before 1990 on Wednesday October 20, 2021 @01:44PM (#28933578)
Interesting.

When I was doing my research on ULPower engines (which can burn 100LL, but they would prefer non-leaded), there were very few airports who offered unleaded fuel (UL94). I think, San Carlos / KSQL was the only one I found?

I wonder what KRHV closure would mean for unleaded fuel? So everybody would just switch back to 100LL? How is that supposed to help?

Wouldn't be more practical (from the point of lead pollution) to enforce non-leaded fuels in those small airports instead? My cursory research shows that lot (?) of these light planes (and, perhaps, the majority of the trainer/weekend hobby aircrafts) would happily burn non-leaded fuel (UL94, for instance), with corresponding STC.

Re:Rust Foundation: Hello, World on Monday February 08, 2021 @03:03PM (#26069388)
>A common way to solve that problem is usually to use references instead of cloning.

Right. I think, we ended up with having everything from the list:

1. String 2. &str 3. Cow<str> 4. Arc<str>, for interned strings (thin Arc would be even better & there is probably a crate for this) 5. Something like owning_ref::ArcRef<Owner, str> 6. One-off tricks where you actually need to construct a new string, but don't want to really construct it (for example, for hash lookup).

#5 I think is undervalued, actually; it's amazing for "enterprise" kind of stuff where you have large trees of data you need to pass around & you don't want to use straight borrowing (like &'a Whatever) because lifetimes are too infectious. And you don't want to use Arc at every corner (like, say, Java would do, not quite, but in semantics).

My problem, though, was to explain all the nuances given that they usually have nothing to do with the "business" part of the problem somebody was solving.

Re:Rust Foundation: Hello, World on Monday February 08, 2021 @01:51PM (#26068446)
I have some extensive (self-assesment :) ) experience building this kind of application, and my answer would be "no, but maybe" (I was one of the first engineers & architect on our zero to ~500k codebase).

Some of the arbitrary, random things I've learned:

1. Given how nice and powerful language is, Rust works relatively well with less experienced engineers. Potentially. You can build very nice APIs which are straightforward to use.

If you can stay in this territory, everything is great.

However, there are some hard walls in Rust which are really difficult to jump over. And once you hit them, you really need somebody who understands Rust really really well and is capable of working around those issues.

2. It was quite hard to find the right balance between engineering time, compilation/linking time, safety, ease of use, performance, etc. Might be my personal biases, but I had to make some questionable decisions to keep compilation times / turnaround times at bay (like, unsound plugin system, custom serialization framework or test framework using nightly Rust features).

3. The type system is really, really nice. This alone compensates for a lot of things.

4. Ecosystem? Simply amazing. High quality libraries, documentation and everything.

5. Ecosystem again? Lots of things are still missing.

6. Performance? I'm 90% trolling here, but my experience was that Rust is not "blazing fast" by default. Not for "enterprise" software. You have to do some legwork sometimes. I've built some simple tool to do certain transformation between JSON and XML, and out of gate it was ~2x slower than Java equivalent (yes, with release build). Turned out, strings are not that cheap to clone if all you have is a bunch of strings. I did make it like 5x times faster than Java in the end, but it did require some weird tricks (like forcing hash map to look for a "derived" key than I give it).

There were some other cases where performance was reduced by simple things (like, having "heavy" Result vs having error variant boxed).

I think, this is "easily" counteracted by adopted practices and libraries (optimized error types, for instance), some standard patterns (like don't be afraid of Arc, they are better than to move huge data chunks around), maybe, good profilers as well.

This is probably also my biases talking here, frankly, I don't think it mattered at all (performance was killed by database, as is very common with enterprise systems). Also, in the end, it was fast (outside of database woes).

7. Overall, I find Rust very exciting language to work with, which was a big driver (but that doesn't necessarily scale -- you'll have to have some answer prepared when less experienced engineers will ask you "but why can't I do like I did in Typescript in those trivial 500 lines of code").

Would I do it again? Probably, but with understanding that whoever pays for it, might be paying for my "fun" on top of the product they are getting. Which is not necessarily a bad thing -- "fun" is also a factor in attraction and retention of engineers.

I'm also not going to lean into the "dark side". Like, if all you care is to get some half-broken whatever out as quick as possible, Rust might not be the right choice. It makes you think about "right or wrong" a lot, imo.

Re:Graphtage: A New Semantic Diffing Tool on Friday August 28, 2020 @10:54PM (#24312967)
At my previous job I've built a tool that was capable of doing that (we were merging XMLs with form definitions). The main idea was an interactive mode.

Initially, tool would merge based on series of heuristics and then user would manually adjust "matching" nodes (user could say "actually, this A on the left and B on the right are the same, it's just that it was heavily modified").

Re:Thoughts on Rust bloat on Thursday August 22, 2019 @12:35PM (#20769832)
Well, I have this anecdote. We switched from serde to our own serialization / deserialization scheme (it still uses serde, but only for the JSON part), which is heavily based on dynamic dispatch, and actually got it faster.

Wasn't apples to apples comparison, but it was some times faster at the time (my memory doesn't serve me, but something around 3x to 5x). Also, compilation speed went down (well, at the time :) ). It was mostly due how some of the features work in serde (flatten and tagged enums), though.

I made a separate, cleaner, experiment (https://github.com/idubrov/dynser), which does not show that dramatic improvement (again, wasn't apples to apples, there were other factors which I don't remember), but shows some.

Re:Metal Lathe Made from Scrap Auto Parts on Sunday March 10, 2019 @11:19PM (#19356404)
I have a small shop. 8x12 lathe, X2 mini-mill, some amount of woodworking equipment (table saw, track saw, etc).

Haven't done anything in the last year or two, though. Turns out, long commute and job at a start-up sucks your soul really hard :(

Though, equipping my machines with power feed taught me Rust and got me in that startup on the first place :D

Re:Rust has a static “garbage collector” on Thursday October 11, 2018 @02:15AM (#18191292)
Yes, the idea is that you only create them temporarily.

Mutability is also possible to some extent with these "smart" pointers. It gets a bit trickier and less ergonomic, though. See https://play.rust-lang.org/?gist=fbf1c24397e7020c95774bf0906...

Another option would be to store something like "Rc<RefCell<Container>>" instead of "&'a mut Container", in which case you will be able to achieve something that behaves like multiple mutable references (with all the concurrency issues of them).

Re:Rust has a static “garbage collector” on Thursday October 11, 2018 @01:01AM (#18191056)
FWIW, it is possible to make it a bit more ergonomic:

  pub struct SmartRef<'a> {
    container: &'a Container,
    widget: usize,
  }
  impl <'a> std::ops::Deref for SmartRef<'a> {
    type Target = Widget; // Widget provides non-traversing functionality
    fn deref(&self) -> &Widget {
      &self.container.widgets[self.widget]
    }
  }
  impl <'a> SmartRef<'a> {
    fn children(&'a self) -> impl Iterator<Item = SmartRef<'a>> {
      self.container
        .widgets[self.widget]
        .children.iter().map(move |w| SmartRef { container: self.container, widget: *w })
    }
  }

  fn boo(container: &Container) {
    let root = SmartRef { container, widget: 0 };
    println!("name: {}", root.name);
    for child in root.children() {
      println!("child name: {}", child.name);
    }
  }
(removed GAT remark -- it does not apply here; was thinking about generalizing this with traits)
Re:Rust has a static “garbage collector” on Wednesday October 10, 2018 @11:30PM (#18190813)
Cloning is not always possible (performance reasons, non-cloneable data, etc) and would not necessarily remove lifetime (for example, it could be a struct, defined somewhere else, with a lifetime parameter).
Re:Rust has a static “garbage collector” on Wednesday October 10, 2018 @08:28PM (#18190119)
>Could you explain? I might need a concrete example.

You might want different trade-offs in different places.

Like, in our case, the conflict is between three different representations:

1. Typed Rust structs 2. Vector with indexes 3. Untyped structs (HashMap of strings to values, essentially)

None of them covers 100% of the use-cases we have (though we also not sure exactly are these the use-cases we will have year from now? three years from now?), and some parts of the system needs to work with all of them.

>Yeah, certainly the refactoring becomes harder (maybe implausible to do automatically) when you can't change both sides in one PR, and when you have to convince someone else to change their interface / bump the major version. It still can be done (partially?) by hand at least; it's just a matter of cost/benefit.

One case was Transaction from postgres crate, which uses lifetime. But I want to stuff it in Arc. Would be possible, if Transaction itself used Arc instead of borrowing, but there are about zero reasons for them to change API that way.

Re:Rust has a static “garbage collector” on Wednesday October 10, 2018 @07:51PM (#18189961)
>Would that satisfy your need?

It's not always possible to change the data structure -- different ways of modeling data have different trade-offs. So, for me it is about not having to make a choice than about tools that will help you to change your mind.

Also, it could be something like structure coming from a 3rd-party crate using borrowing and you want to stick it into "Arc" of some sort. Or put it (with the thing it borrows from) into a lifetime-less struct, so you don't have to care about these lifetimes.

>IMHO, this is a valid use case for Rust.

I very much hope so :)

Re:Rust has a static “garbage collector” on Wednesday October 10, 2018 @07:15PM (#18189779)
#4 highly depends on a project size. On big projects, some of these decisions might become effectively one way doors.

I've been struggling a bit with these issues on the project of ~70k lines. I cannot even imagine what the refactoring would look like if we had, let's say, 1 million LOC.

To be fair, though, we use Rust the way it wasn't specifically designed for (large "enterprise" software, think Java-like enterprise).

I think, potentially, Rust could offer a much better story for this kind of software (assuming we are not mad and the issues we are facing are not because we doing something completely wrong :) ). In my opinion, the key thing would be to allow building "bridges" between pieces of the system which are "ownership-incompatible", so your decisions around ownership are not "one way doors" anymore (at the cost of translation / adapter layer).

Some random things which I think would be helpful:

1. Better self-referential structs, to allow going from "owned A + borrowed B" into "fully owned A+B" (rental crate helps here, though). Basically, hiding lifetimes in scenarios where you cannot easily change the original data structure to "own".

2. GATs. Honestly, this one is my speculation, but it seems like certain patterns which are hard to express now (abstraction of a "mutable reference", for example) would be possible with GATs. In our case, this would allow to bridge the gap between "trait object" world and "parametric over trait" world. The issue I was having is it is hard to express "mutably borrow from self" with traits (this is something similar to the issue "streaming iterator" crates solves). I was able to hack something using arbitrary self types, but it's quite... hacky.

3. Trait objects stable(r) ABI. Again, purely my speculation, but would allow to go back from "trait reference" world into "trait object" world. I won't go into details here, but trait objects want to "borrow" from something and it is not always easily possible (think that favorite vector+indices data structure) -- being able to "fake" those borrows would be nice (maybe).

Issues #2 and #3 specifically happens around deciding on data structure: regular structs have one set of tradeoffs, vectors with indexes -- another. In a big enterprise software, I would like to have an option to use whatever works in a particular spot and still have it API-compatible to the rest of the system.

Any comments on how FoundationDB might be the same / different?
Re:Understanding OAuth 2.0 and OpenID Connect on Monday April 30, 2018 @04:47PM (#16962172)
They are in the same category as mobile apps in that respect, no? Both of them are "public clients" in terms of OAuth 2.0.
Re:Understanding OAuth 2.0 and OpenID Connect on Monday April 30, 2018 @03:31PM (#16961504)
I wonder if the same recommendation (use Authorization Code Grant flow plus PKCE instead of Implicit Grant) should be made for SPA (single page applications), too.
Re:Ask HN: What books do you keep on your desk? on Wednesday April 04, 2018 @02:54PM (#16757744)
1. Digital Design and Computer Architecture: ARM Edition

2. The Evolution of Cooperation: Revised Edition

3. The Ego Tunnel: The Science of the Mind and the Myth of the Self

(in backpack until I finish it). The Lucifer Effect: Understanding How Good People Turn Evil

Re:Embedded in Rust: Brave new I/O on Saturday January 20, 2018 @12:18AM (#16192198)
I don't see anything controversial here.

First, you can always use unsafe and access low level registers ignoring all the synchronization. You are still getting typed access to the bits (well, contingent on SVD file quality), which is an improvement over hand-writing bit manipulation code (or using wrong constant for shift/mask in STM32 HAL, for example).

Second, look at the port splitting example. If you split port into pins, when you can independently move these pins into different execution contexts and you won't need any synchronization as well. Write to a pin would be a single write to BSRR register -- no read-modify-write. So you are getting safety and about the same generated code as for hand-written code (well, except that if you want to do multiple pins at once).

What if you want to reconfigure port? This is, actually, what was particularly annoying for me with the old version of svd2rust I/O. Even though I know that my two subsystems operate on completely different pins, I still had to pass CRL/CRH around, to avoid potential race when reconfiguring pins.

This new version has the same property, though, -- according to the article.

However, the solution is pretty straightforward. By using ARM bit-banging feature, you can have the same "split" atomic-share-nothing-style API for the port reconfiguration, too. Similarly, you would split, for example, GPIOA into 8 pins and each pin would allow you to both input/output data and change port direction.

So, bottom line, I think you can get best of both worlds most of the time: safety and performance of the hand-written code. And in corner cases, you can still ignore all the safety and access registers without any overhead.

I don't really understand what is this approach lacking for career firmware engineer.

(disclaimer: I haven't ported my firmware yet, so I could be wrong in my assumptions how this new I/O works).