12

I'm working on a port from Python to Rust and ran into some code that can't be expressed as naturally in Rust as they can in Python.

One case of this is using default parameters:

class Foo:
  def __init__(self, a="Hello"):
    self._a = a

In Rust, you might implement this using a builder:

struct FooBuilder {
  a: &'static str,
}

struct Foo {
  _a: &'static str
}

impl FooBuilder {
  fn new() -> FooBuilder {
    FooBuilder {
      a: "Hello",
    }
  }

  fn change_a(self, new_a: &'static str) -> FooBuilder {
    FooBuilder {
      a: new_a,
      ..self
    }
  }

  fn build(self) -> Foo {
    Foo {
      _a: self.a,
    }
  }
}

To use the class in Python, it's simply:

foo = Foo("Hello, World!")

However, in Rust, you would need to write something like:

let foo = FooBuilder::new().change_a("Hello, World!").build();

This leads to the question: is it better to maintain an API for a port, or is it better to use idioms of the porting language? Does it depend on how well-known the API is to begin with?

  • 2
    The API of a class is how you use it, not how it is expressed in code. So, that translation has a starkly different and simply unacceptably cumbersome ABI. – Deduplicator Dec 18 '15 at 17:01
  • Where is it said that that's idiomatic Rust? – Nadir Sampaoli Dec 18 '15 at 19:33
  • I'm sorry, I must have misunderstood. You posted some Rust code, along with a dilemma: weather you'd maintain an API for a port or you'd use idioms of the porting language. That code doesn't look like either of those cases. If this is the correct interpretation, what's the purpose of that code sample? What is it describing and how does it relate with the actual question? – Nadir Sampaoli Dec 18 '15 at 20:08
18

You want your ideas expressed clearly in the language that hosts them. That means using host language idioms.

Take the popular Underscore library: js and lua. The lua port is functionally equivalent for the most part. But when it's appropriate, implementations are slightly different. For example:

_.toArray()

becomes

_.to_array()

This change makes the function name feel more native to Lua programmers.

Likewise, _.each() requires an object, array, or something array-like in JavaScript, but _.each() in Lua can also take an iterator -- a mechanism that wasn't available in JavaScript when the original Underscore library was created.

The Lua author sensibly translated what the original author would have intended if they had written it in Lua. That's the key. Ask yourself about the original intent and then implement that intent in your language of choice -- idioms and all. Depending on the source and target language, this can mean adding, editing, or removing features.

Remember that cross-language users will be rare. Most users will use one language or the other. For them, the differences don't matter. If someone uses both, they're probably sophisticated enough to appreciate your translation. It's no different than translating spoken languages. Some ideas aren't directly translatable. The best translators stick to the intent of the original, not a doomed word-for-word literal translation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.