> Personally, I don't see the harm in supporting it.  If someone's going to 
abuse it, they'll abuse Enum.at()

The harm isn't for people who doing it intentionally, the harm is for 
people who are doing it unintentionally. Index based array access is so 
common in certain languages that it's one of the first thing newbies from 
those languages will try in Elixir and if it works then they'll just 
proceed writing loops like:

for i <- 0..length(users) do
  IO.puts users[i].name
end

In doing so they'll have reinforced a non idiomatic pattern, and failed to 
learn something crucial about the language. Of course they can always hit 
the docs and find Enum.at and rewrite it, but if you google: "Elixir access 
list by index" you get stack overflow and forum posts that help you realize 
that you probably don't want to do that. If [] just works they won't google 
till much later.

- Ben

On Friday, September 22, 2023 at 4:28:47 AM UTC-4 ...Paul wrote:

> On Thu, Sep 21, 2023 at 7:19 PM 'Justin Wood' via elixir-lang-core <
> elixir-l...@googlegroups.com> wrote:
>
>> Languages that support it via square brackets: Rust, Ruby, Javascript, 
>> Python, C, Julia.
>>
>> All of these languages (other than maybe Julia? I have not used it at 
>> all.) are actually using arrays and not lists. It is fairly natural to have 
>> easy index based lookup for arrays. After all, it is meant to be a 
>> contiguous block of memory with each element having a known size. At least 
>> for Rust and C, other languages may be more loose in terms of 
>> implementation.
>>
>
> That's the problem.  Ruby, Python, Javascript are where a lot of Elixir 
> devs are coming from (or languages that Elixir devs are often "context 
> switching" with on a daily basis) and these all implement lists that are 
> not actually arrays in the conventional sense.  I'm pretty sure, in all 
> three cases, that a list is actually an object that maintains the list 
> elements -- that might be an actual array of pointers, or it might not.  
> It's definitely not a low-level single allocated block of memory, because 
> these are weakly typed languages an all three support mixed type values (an 
> array in C requires every entry be a fixed size; indexed access is simply 
> multiplying the index by the size of each element and using that as an 
> offset to the start of the memory block -- one of the reasons you can 
> easily segfault by doing that).
>
> Lists in Elixir are linked lists, but we don't regularly refer to them 
> that way.  We don't explicitly reinforce this implementation by requiring 
> things like "LinkedList.new(1, 2, foo)"; we use a "conventional array 
> notation" like "mylist = [1, 2, foo]" -- just like you'd see in Python, 
> Javascript, Ruby.  So it's really not that much of a surprise, coming from 
> those languages, that you start off with that kind of a syntax, and you 
> then expect the language to implement square-bracket-indexing, just like 
> those languages do.  We have Enum.at() to do this, so it's not like it's an 
> impossibility to actually make this work.  The question then is why the 
> syntax doesn't just wrap that function and 'make it work'.  I'm not sure I 
> buy Jose's argument about preventing "non-idiomatic code".  If someone is 
> going to forget that Enum.map exists, they're going to write that loop, and 
> they'll just use Enum.at if they can't get the square brackets to work.
>
> This difference from how those languages have wrapped array-like functions 
> into their syntax has popped up recently with my team, we've noticed people 
> forgetting that the length of a List in Elixir isn't "free information" 
> like it is in Ruby (where the length of a list is actually an attribute of 
> the object representing the list), so we've had to remind people not to do 
> things like "assert length(foo) > 0" (fortunately, a lot of this 
> inefficiency has been limited to our unit tests!) -- because they're coming 
> from Ruby where the length of a list is always "known", so it doesn't even 
> occur to them (and I admit, I've been guilty of forgetting this 
> occasionally as well) that Enum.count() and length() both actively loop 
> over an argument to compute the length, and aren't just retrieving some 
> privately cached data.
>
> As an aside, the one oddity around Access' square-bracket-index 
> implementation that still throws me every once in a while is why you can't 
> use square brackets to index a field on a struct.  If you have a Map, you 
> can do foo[key] but on a struct, foo[key] throws an exception.  Where it 
> gets annoying is that the way to make this work on a struct is to actually 
> use Map.get -- a Map function!  If a struct is a Map, why can't Access just 
> treat structs like Maps in this situation?  But that's a completely 
> different discussion, and I digress.  ;)
>
> Personally, I don't see the harm in supporting it.  If someone's going to 
> abuse it, they'll abuse Enum.at() to make it work anyway, just like I end 
> up abusing Map.get() when I need to get a field from a struct based on a 
> variable key name.  But it's definitely going to be an ongoing point of 
> confusion because "one of these things is not like the others"
>
> ...Paul
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elixir-lang-core+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/fc39f33d-7b61-46dd-9980-f8e54de63dc8n%40googlegroups.com.

Reply via email to