Live data from Hacker News

ElixirNitpicks

wiki.alopex.li

41–50 of 60 posts

Re: ElixirNitpicks

#41

Earlier quoted context omitted.

iex(1)> a=10 10 iex(2)> a=11 11 Because underneath, it’s doing A0 = 10. A1 = 11. You might not like it, because it feels like mutation, but it’s not, it’s rebinding. Just consider this as a syntactic sugar. It’s useful when doing conn = conn |> apply_some_change() In the end, it does generate valid bytecode for the BEAM, and immutability is respected. BTW You might prefer Erlang syntax, but You would lose |> José Val…

Genuine question: From an application developer's perspective, what's the difference between mutating a value and transparently rebinding an old name to a new value? Is it just that in the latter case other references don't pick up the changes? So with rebinding we don't have something like a = 10 b = a a = 11 print(b) // 11 ?

    def func() do
       a = 10
       def func2() do 
           a + 1
       end
       a = 20
       func2()
    end
Mutation would have func() return 21. Rebinding has it return 11.

Likewise, mutating languages typically allow for a method to modify its arguments when those arguments are objects

    public void modify(MyObject a){
         a.changed = true;
    }

    public bool test_modify(){
         MyObject b = new MyObject();
         b.changed = false;
         modify(b);
         return b.changed
    }
test_modify will return true in languages that allow mutation.

Re: ElixirNitpicks

#42
post #11

> I do wish migrations were just generated from schemas though, a la Django. This is a weird one to me. I really dislike the magical way Django does this and I'm glad Ecto doesn't. It also allows you to have separate Ecto structs representing different parts of a table in scenarios where that is desirable.

Agreed, I hate the way Django does it. I don't want my database migrations to be tightly coupled to my models - what's the point? I'm not sure that the Django approach would make sense in Ecto anyway because Ecto schemas are explicitly _not_ "models". The function of a Django/Rails "model" is divided between different concepts like schemas, Ecto.Query, Ecto.Changeset, the Repo etc.

Same. I was annoyed at first with what felt like duplication (and indeed is duplication for the first time the table is created), but over time the Ecto/Elixir method really showed it's merit and is IMHO the cleary superior way for a maintainable long-term application. The magic and the convenience in the short term it brings are not worth it. The straight forward, explicit and crystal clear declarative way for migrations and the schema are IMHO a joy.

Re: ElixirNitpicks

#43

Earlier quoted context omitted.

There was something like this a few years ago, "Elixir for Rubyists": https://thoughtbot.com/blog/elixir-for-rubyists

I wrote something similar here: https://phoenixonrails.com/blog/elixir-for-ruby-developers-t... https://phoenixonrails.com/blog/elixir-syntax-for-ruby-devel...

Disclaimer: This is my talk/video

If you like the presentation format rather than written format, I did what was called by one reviewer "a delightfully thorough" intro to Elixir for Rubyists: https://www.youtube.com/watch?v=uPWMBDTPMkQ

Re: ElixirNitpicks

#44
post #32

Glad I'm not the only one who doesn't get Ecto.Multi. I can see how it's useful in theory in some cases, but I've always found it much easier just to use Repo.transaction.

I think Multi could use some improvements but it has its uses distinct from transactions especially around he ability to do introspection.

Re: ElixirNitpicks

#45
post #25

Testing is one of the areas that we have felt the most in Elixir while building Batteries Included. ExUnit is pretty good, but bare bones. That combined with Phoenix (most popular web framework in elixir) made for some places we didn't test. So we created a test library that does polaroid snapshot testing of Phoenix components. We called it Heyya and added other utilities to test phoenix live view too. Does anyone ha…

What do you mean testing with processes? I won't suggest these are the best written tests, but I test various processes, supervisors, etc like this: - https://github.com/cpursley/walex/blob/master/test/walex/sup... - https://github.com/cpursley/walex/blob/e13a9cbf9aca1a2a2d4ed...

If have an `Application` that starts processes that cache ecto state, or periodically write to db, etc, it's hard to test the whole process tree. Additionally Umbrella projects start all applications in the project with one config. All of those combined mean you have to change your code structure quite a lot to make that testing possible.

Testing single processes is pretty easy. Making sure that two processes and ecto can tolerate failures, delays, etc requires too much.

Re: ElixirNitpicks

#46
Well, I had a comment, but was apparently too long, so I've placed it into a gist for now https://gist.github.com/IceDragon200/b71cafd052ee03f65d1cadc...

For the email validation I would have used an ecto schema, since most cases you won't just be validating an email address in isolation:

  defmodule EmailSchema do 
    use Ecto.Schema

    import Ecto.Changeset

    @primary_key false

    embedded_schema do 
      # here is your type validation right off the bat
      field :email, :string
    end

    def validate(email) do
      %__MODULE__{}
      |> cast(params, [
        :email,
      ])
      |> validate_required([
        :email,
      ])
      |> validate_change(:email, fn :email, value ->
        cond do
          not is_email_address?(value) ->
            [email: {"invalid email address", [validation: :email]}]

          not EmailAddresses.is_available?(value) ->
            [email: {"is unavailable", [validation: :email]}]

          true ->   
            []
        end
      end)
      |> apply_action(:insert)
    end
  end

  case EmailSchema.validate(email) do 
    {:ok, %{email: email}} ->

    {:error, %Ecto.Changeset{} = changeset} ->
      changeset.errors[:email] 
      # Can be all of these in the same list, or be any one depending on the validations
      #=> [{"is required", [validation: :required]}]
      #=> [{"invalid email address", [validation: :email]}]
      #=> [{"is unavailable", [validation: :email]}]
  end

Re: ElixirNitpicks

#47
post #2

Interestingly, though I am not a great Rust programmer, nor a great Elixir programmer (I have written programs in both languages). And, gotten a little ways through the amazing Exercism ( https://exercism.org/tracks/elixir ). What I loved about this writeup was the way I could review both by comparing two languages in which I have a moderate understanding. The comparison of imports was very engaging to my brain. I re…

There was something like this a few years ago, "Elixir for Rubyists": https://thoughtbot.com/blog/elixir-for-rubyists

I'm not the author of the book, but I bought and enjoyed it quite a bit.

https://pragprog.com/titles/sbelixir/from-ruby-to-elixir/

From Ruby to Elixir, by Stephen Bussey. He's also written a book named Real-time Phoenix which I also found pretty helpful.

Re: ElixirNitpicks

#48

Earlier quoted context omitted.

Genuine question: From an application developer's perspective, what's the difference between mutating a value and transparently rebinding an old name to a new value? Is it just that in the latter case other references don't pick up the changes? So with rebinding we don't have something like a = 10 b = a a = 11 print(b) // 11 ?

def func() do a = 10 def func2() do a + 1 end a = 20 func2() end Mutation would have func() return 21. Rebinding has it return 11. Likewise, mutating languages typically allow for a method to modify its arguments when those arguments are objects public void modify(MyObject a){ a.changed = true; } public bool test_modify(){ MyObject b = new MyObject(); b.changed = false; modify(b); return b.changed } test_modify will…

This is a great example of why the pin-operator is bad, IMO. Rebinding isn't worth this complication.

Re: ElixirNitpicks

#49

Earlier quoted context omitted.

def func() do a = 10 def func2() do a + 1 end a = 20 func2() end Mutation would have func() return 21. Rebinding has it return 11. Likewise, mutating languages typically allow for a method to modify its arguments when those arguments are objects public void modify(MyObject a){ a.changed = true; } public bool test_modify(){ MyObject b = new MyObject(); b.changed = false; modify(b); return b.changed } test_modify will…

This is a great example of why the pin-operator is bad, IMO. Rebinding isn't worth this complication.

On the contrary. I'd like the pin operator regardless of whether rebinding is allowed or not.

    def func() do
      s = g()
      ...several lines of code
      l = t()
      case l do 
         {s, q} -> #blah
         {q,q} -> #blah
         {p, r} -> #blah
      end
    end
Without the "^s", you need context to determine "s"'s behavior. If s is currently unbound, then it'd be assignment. If it's unbound, it'd be pattern matching. It's a rare enough operation that it's nice to make it explicit.

Erlang didn't have rebinding, and Elixir learned from the mistake. Rebinding is not complicated: the scope rules are simple, you learn them and then you're done. It's Day 1 type stuff, which is absolutely not worth optimizing for if you're trying to build a useful language. Without them, you end up coming up with a bunch of bogus variable names that don't add anything to the conversation. Imagine modifying an entry in a struct (or, more exactly, you're making a copy of a struct with one value changed)

With rebinding, it's easy:

    def func(dict) do
      dict = dict |> Map.put("apple", 1)
    end
Without rebinding, you need a pointless new variable name:

    def func(dict) do
      dict_with_one_apple = dict |> Map.put("apple", 1)
    end

Re: ElixirNitpicks

#50
> Lots of other tools are a bit short of the “first-class” level of polish; Image/Vix

I'm the author of Image and I'd welcome feedback on improving areas where you see lack of polish (there's a reason its not yet 1.0, but it is getting closer - primarily rewriting the color model).

Comments here are fine, or in the repo at https://github.com/kipcole9/image

Post reply on HN