
Gnirehtet rewritten in Rust - rom1v
https://blog.rom1v.com/2017/09/gnirehtet-rewritten-in-rust/
======
im_down_w_otp
When I write Rust I tend to do so using functional/procedural patterns instead
of object-oriented ones, and it doesn't seem like I run into issues like the
ones described here very often.

Much of this write-up seems to cover things that were/are complicated because
of OOP's tight coupling of state and actions on that state & the intersection
of that with the additional constraints and controls Rust places on state
management.

I'm not entirely sure which style/patterns are more idiomatic. I just know
which ones keep me out of trouble.

~~~
bluejekyll
I don’t know about this. I think the trait system is so powerful of a concept
for genetics and such that I find that I practice OO pretty regularly. I avoid
dynamic polymorphism, but most OO practices translate really well into Rust.

~~~
sixbrx
Sounds closer to type classes usage a la Haskel than what I'd call OO (late
binding)?

~~~
bluejekyll
I try to capture data in a enum or struct, then define the operations
available to that type. A trait allows me to capture common functionality
across different types which implement that trait. With generics it allows me
to be polymorphic.

If that’s not OO, I don’t know what is :)

~~~
Tarean
Well, technically traits dispatch based on type and not on value. As long as
you aren't wrapping everything into trait objects that is much closer to
functional programming. Seems like a mostly semantical difference, though.

I guess there is a philosophical difference in whether you pass a large struct
into a function or select the needed data at the call side and only pass that,
though. Former might be easier to extend, latter is probably easier to test?

------
solidsnack9000
The discussion of how borrowing impacts encapsulation, abstraction with
private methods, and the observer pattern was informative and interesting.

~~~
oconnor663
I think the part where they're trying to abstract out a `content` method could
be made to work by adding braces, so that the `&self` borrow goes away earlier
than the end of the function. I think "nonlexical lifetimes" are also going to
make more cases like that work automatically without braces soon.

~~~
rom1v
> I think the part where they're trying to abstract out a `content` method
> could be made to work by adding braces, so that the `&self` borrow goes away
> earlier than the end of the function.

Not in that case. It helps when dropping a borrow earlier avoids to violate
the borrowing rules, like in this case:

    
    
        let mut a = [0; 20];
        {
            let b = &mut a[2..4];
        }
        let c = &mut a[6..8];
    
    

In the example from the blog post, content borrows the whole struct, and you
can't drop the borrow earlier since it is used in the next line.

~~~
oconnor663
Right, you'd have to split up the following line so that `sum` is computed
inside the block but assigned after it.

------
viraptor
I think in the encapsulation / content example they missed the possibility of
creating an explicit block on your own. I believe something like this would
solve it:

    
    
        let new_sum = { calculate it from self.content() }
        self.sum = new_sum;
    

Since the sum value itself doesn't borrow anymore.

~~~
rom1v
Yes, you're right, this particular (artificial) example could be rewritten
easily so that it compiles.

But the point was to show that a compiling program may not compile anymore
after factoring some code into a private method.

~~~
fnord123
Is the purpose of encapsulation to wrap all data fields in functions offering
mutable references to data? I thought it was the exact opposite.

~~~
rom1v
The purpose was to show that something lifetime-bound to _a part of_ a struct
becomes lifetime-bound to _the whole_ struct when returned from a function.

Using mutable references is the minimal way to get this.

------
steveklabnik
Apparently the name is "tethering" backwards.

~~~
saghm
Embarrassingly, it took me until halfway thorough the article to notice this

------
akavel
Is there some valuable disscussion of the article on rust subreddit? If yes,
could somebody please link it here?

~~~
txru
[https://www.reddit.com/r/rust/comments/71ks57/gnirehtet_a_re...](https://www.reddit.com/r/rust/comments/71ks57/gnirehtet_a_reverse_tethering_tool_for_android/)

------
mathw
The "encapsulation" example is an interesting one, because it sits right in
the fundamental difference between a Rust reference and a Java one, and the
lifecycle considerations of a garbage-collected language vs one where
lifecycles are statically determined by the compiler.

I guess one way to explain it, if one needed to, is to say that the Java
object is effectively a collection of Rc<RefCell<T>>, and getters return
copies of those Rc<>s. (Okay I know, garbage collection is not the same as
refcounting, but in this kind of analysis it's effectively the same).

Makes me sit back and think how much work Java the language is doing for you
here.

------
pjmlp
> ... I introduced Gnirehtet, a reverse tethering tool for Android I wrote in
> Java.

> At Genymobile, we wanted Gnirehtet not to require the Java Runtime
> Environment, so the main requirement was to compile the application to a
> native executable binary.

While it is nice to see new projects adopting Rust, I really don't get the
point of having a tool targeted to Android developers not depending on Java.

~~~
harrisi
As far as I can tell it's not necessarily targeted at Android developers. It
seems like the primary use case is if you have some device with cell service
and you're out of WiFi range but want to use your Android device with an
internet connection.

They must have customers that are in that situation somewhat regularly
(traveling business people?) and keeping the overhead low is desired.

------
tango25
Hello Gnirehtet is really a great tool.

Is there a possibility to have the RUST Version compiled for an ARM
architecture?

I'm running it on a Raspi3 as a tether box. Obviously less CPU consumption
would be an enormous advantage. , since with the java version transmit speed
only reaches arround 50 kbit/s.

Thank you very much for your great work!

~~~
steveklabnik
It should work, yeah.

~~~
tango25
Awesome! will you put a executable at GitHub like the others? Thank you very
much!

~~~
steveklabnik
I'm not the maintainer of the project, so I can't do that. Rust can cross-
compile to that architecture though, so it should be possible, hence my reply.

You probably should file an issue so the maintainer actually sees it.

~~~
tango25
Here it is! Awesome!
[https://github.com/Genymobile/gnirehtet/issues/46](https://github.com/Genymobile/gnirehtet/issues/46)

------
matt_wulfeck
> _At Genymobile, we wanted Gnirehtet not to require the Java Runtime
> Environment, so the main requirement was to compile the application to a
> native executable binary._

While I think that rust is a great choice, if multi platform static
executables is your goal then I think you missed a language that does such a
thing extrmely well. I’m surprised the author didn’t even consider Go for this
purpose.

~~~
stouset
You may have missed these three points the author listed, favoring Rust:

    
    
      * memory safety without garbage collection,
      * concurrency without data races,
      * abstraction without overhead
    

Go has garbage collection, doesn’t statically prevent data races, and somewhat
infamously allows for only minimal abstraction.

~~~
lossolo
You should reread article again:

> But at that time (early May), I was interested in learning Rust, after
> vaguely hearing what it provided, namely:

And then he listed what you listed in your comment.

As he wrote the main requirement was not to include JRE. This could also be
achieved by using Go.

