Actually, that what I understood only in my last message - I can implement
it right now. I'm pretty new to Elixir, so that wasn't obvious to me.

Currently, it seems it's resolved, there are only suggestions to improve
syntax, that are too minor.

Thank everyone for assistance

On Wed, Nov 7, 2018 at 9:15 PM Louis Pilfold <[email protected]> wrote:

> Hi Sergiy
>
> I'm afraid I don't follow. From what I understand of your proposal the
> current defguard system meets your needs- what are you looking to add?
>
> Cheers,
> Louis
>
> On Wed, 7 Nov 2018 at 18:38 Sergiy Kukunin <[email protected]>
> wrote:
>
>> I afraid you missed my point, I might have expressed it poorly. Let's
>> assume I have a simple type: {is_atom(), is_number(), is_binary()}. I want
>> to define a guard to match it. Without reusing I can write a function
>> accepting it:
>>
>> func({x, y, z}) when is_atom(x) and is_number(y) and is_binary(z), do:
>> true
>>
>> but then I want to define another function which expects the same tuple:
>>
>> another({x, y, z}) when is_atom(x) and is_number(y) and is_binary(z), do:
>> true
>>
>> I don't have a way to define a custom guard to match tuple elements since
>> there is no pattern matching in defguard nor there is `elem` in guards. So
>> both options don't work:
>>
>> defguard is_mytype({x, y, z}) when is_atom(x) and is_number(y) and
>> is_binary(z)
>>
>> nor
>>
>> defguard is_mytype(x) when is_atom(elem(x, 0)) and is_number(elem(x, 1))
>> and is_binary(elem(x, 2))
>>
>> Furthermore, I would want to define a function that receives a value of
>> my type inside of complex structure:
>>
>> function({:ok, {x, y, z}}) when is_atom(x) and is_number(y) and
>> is_binary(z), do: true
>>
>> it would be cool to have it defined as
>>
>> function({:ok, x}) when is_mytype(x), do: true
>>
>> P.S. Actually, I've found that `elem` works in guards, so I can define my
>> guard without pattern matching. That's good for now, but
>>
>> func({x, y, z}) when is_atom(x) and is_number(y) and is_binary(z), do:
>> true
>>
>> sounds cooler, IMHO =)
>>
>> On Wednesday, November 7, 2018 at 8:20:22 PM UTC+2, Louis Pilfold wrote:
>>
>>> Hi Sergiy
>>>
>>> The functionality you've described can be implemented with macros, no
>>> need to modify Elixir or Erlang.
>>>
>>> To start it could be as simple as defining guards that assert nothing in
>>> the production environment.
>>>
>>> defmodule Test do
>>>   if Mix.env() == :prod do
>>>     defguard is_my_type(x) when true
>>>   else
>>>     defguard is_my_type(x) when is_atom(x)
>>>   end
>>>
>>>   def go(x) when is_my_type(x) do
>>>     x
>>>   end
>>> end
>>>
>>> This could be a little error prone though as unless you remember to
>>> apply the guard to every clause of the function your logic may change when
>>> they are removed. Even if you apply them to every clause if you use
>>> exceptions as flow control you may run into problems as values that
>>> previously would result in a FunctionClauseError would be passed though.
>>>
>>> Plenty to think about! Perhaps experiment with a little proof of concept
>>> library and see what happens :)
>>>
>>> Cheers,
>>> Louis
>>>
>>> On Wed, 7 Nov 2018 at 17:44 Sergiy Kukunin <[email protected]> wrote:
>>>
>> Thanks for the answers. Just want to note, that I don't want to invent
>>>> type system such as in statically typed languages. I mean more about
>>>> defining schemas we can check different values with. All pattern matching,
>>>> guards and typespec might work for this. Furthermore, it would be cool to
>>>> make it composable and reusable (such as defguards and typespecs right 
>>>> now).
>>>>
>>>> Just to conclude, I would suggest that either of these would improve
>>>> the safety and convenience of the language:
>>>> - allow pattern matching in custom guards (either via the built-in
>>>> guard such as `Kernel.match?/2` or by extending the defguard syntax)
>>>> - having a macro to check whether a value corresponds to a defined @type
>>>>
>>>> What's about such syntax?
>>>>
>>>>  defguard is_mytype({x, y}) when is_atom(x) and is_number(y)
>>>>
>>>>  def test({:ok, value}) when is_mytype(value), do: true
>>>>  def test(_), do: false
>>>>
>>>>  test({:ok, {:hello, 5}}) # should be true
>>>>  test({:ok, {2, 5}})  # should be false
>>>>
>>>> There are a couple of reasons I've raised this question:
>>>>
>>>> - do I miss something? don't I try to solve the problem in a wrong way?
>>>> - to estimate how hard is it to implement in a 3rd-party library or
>>>> does it require changes to core Elixir/ErlangVM
>>>>
>>>> Thanks
>>>>
>>>>
>>>> On Wednesday, November 7, 2018 at 7:20:47 PM UTC+2, Louis Pilfold wrote:
>>>>
>>>>> Hi all
>>>>>
>>>>> The desire for more safety in Elixir is reasonable, both at compile
>>>>> time and at runtime.
>>>>>
>>>>> The core team have previously experimented with introducting a compile
>>>>> time type checking system, and we also have the dialyser and gradualizer
>>>>> tools that can be used with Elixir.
>>>>>
>>>>> Checking at runtime is something we already do in Elixir and Erlang
>>>>> through the use of pattern matching and guards such as `is_binary/1`.
>>>>> A library of macros that automates these checks could be an
>>>>> interesting project, perhaps an area worth exploring for members of the
>>>>> community.
>>>>>
>>>>> Cheers,
>>>>>
>>>> Louis
>>>>>
>>>>> On Wed, 7 Nov 2018, 16:46 Ivan Yurov, <[email protected]> wrote:
>>>>>
>>>> If you want type-safety why not to just pick a strongly typed language,
>>>>>> like Ocaml for example? Elixir is bound to Erlang VM and will never 
>>>>>> provide
>>>>>> any features like you're describing that are not supported by Erlang. 
>>>>>> And I
>>>>>> don't think type-checking ever happens at runtime in any language.
>>>>>>
>>>>>> On Wednesday, November 7, 2018 at 12:00:53 PM UTC+1, Sergiy Kukunin
>>>>>> wrote:
>>>>>>>
>>>>>>> Hello there. This is my first message to the elixir group. Thanks
>>>>>>> for the great language.
>>>>>>>
>>>>>>> While I'm writing my code, I want to make functions to be safer.
>>>>>>> It's bad practice if a function accepts unexpected input and pass it
>>>>>>> further, and it blows in a completely different part of a system.
>>>>>>>
>>>>>>> At first glance, I have pattern matching, but it's pretty limited.
>>>>>>> It becomes really powerful in conjunction with guards, so I can write a
>>>>>>> signature to match literally everything.
>>>>>>> But they hard to re-use, If I have multiple functions operating with
>>>>>>> the same object. Yes, I can define a custom guard, but can I use pattern
>>>>>>> matching there? `Kernel.match?/2` doesn't work, so I'm limited with only
>>>>>>> guards in my custom guards.
>>>>>>>
>>>>>>> Another thing that we have typespecs. It seems exactly what I'm
>>>>>>> looking for: you have a wide set of built-in types, and I can easily
>>>>>>> compose and reuse my own types. The problem with it, that it doesn't 
>>>>>>> affect
>>>>>>> runtime. I know about static analyzer `dialyzer`, but I'm not sure it 
>>>>>>> will
>>>>>>> catch all cases since it's a static check, not a runtime.
>>>>>>>
>>>>>>> Let's assume a simple function, that wraps a value into a list:
>>>>>>>
>>>>>>>   @spec same(number()) :: [number()]
>>>>>>>   def same(number) do
>>>>>>>     [number]
>>>>>>>   end
>>>>>>>
>>>>>>> I'm sure the `dialyzer` won't complain since a signature is valid.
>>>>>>> But what if I do: `same("abc")` ? What will prevent Elixir from 
>>>>>>> returning a
>>>>>>> wrong type? I guess, nothing.
>>>>>>> An example from a real life: I have a function, that accepts a
>>>>>>> custom shaped value (using tuples) and feeds it to a queue. Then, in the
>>>>>>> totally different part of the system, a consumer gets values from the
>>>>>>> queue. And when a wrong value was fed on the producer side, it blows on 
>>>>>>> the
>>>>>>> consumer side. So I decided to put some constraints on the producer 
>>>>>>> side to
>>>>>>> fail fast.
>>>>>>>
>>>>>>> Yes, I could define a guard, but again, if I have a pretty complex
>>>>>>> type instead of the simple `number`, I had to duplicate the type 
>>>>>>> defining:
>>>>>>> one for typespec, another is for a custom guard (which is limited, 
>>>>>>> since I
>>>>>>> can't use pattern matching there).
>>>>>>>
>>>>>>> Wouldn't it be cool, If we had a mechanism to assert a value to its
>>>>>>> type, in runtime? To avoid performance penalty we could enable it only 
>>>>>>> for
>>>>>>> runtime. Is there a way right now to check whether a value corresponds 
>>>>>>> to a
>>>>>>> type in runtime? Can I implement a custom macro to provide a good DSL 
>>>>>>> for
>>>>>>> this? Is it helpful at all?
>>>>>>>
>>>>>>> P.S. You may say, use structs and pattern matching would work in
>>>>>>> this case. But what if my type is better represented by a tuple: 
>>>>>>> {atom(),
>>>>>>> pos_integer(), string()}. Converting it to a struct might complicate a 
>>>>>>> way
>>>>>>> to work with the value.
>>>>>>>
>>>>>> --
>>>>>> 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 [email protected].
>>>>>
>>>>>
>>>>>> To view this discussion on the web visit
>>>>>> https://groups.google.com/d/msgid/elixir-lang-core/8c4d9dac-134d-471c-a402-e9696bf5aecf%40googlegroups.com
>>>>>> <https://groups.google.com/d/msgid/elixir-lang-core/8c4d9dac-134d-471c-a402-e9696bf5aecf%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>> .
>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>
>>>>> --
>>>> 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 [email protected].
>>>>
>>> To view this discussion on the web visit
>>>> https://groups.google.com/d/msgid/elixir-lang-core/c7e602a5-a694-46f9-99a5-983b4d50eea0%40googlegroups.com
>>>> <https://groups.google.com/d/msgid/elixir-lang-core/c7e602a5-a694-46f9-99a5-983b4d50eea0%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>> For more options, visit https://groups.google.com/d/optout.
>>>>
>>> --
>> 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 [email protected].
>
>
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/elixir-lang-core/f6a0f326-ffa4-4b69-998d-6f60a91abe87%40googlegroups.com
>> <https://groups.google.com/d/msgid/elixir-lang-core/f6a0f326-ffa4-4b69-998d-6f60a91abe87%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "elixir-lang-core" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/elixir-lang-core/fvn29FjvSks/unsubscribe
> .
> To unsubscribe from this group and all its topics, send an email to
> [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/elixir-lang-core/CABu8xFBC%3DM6s0p9po2CsoWXQ-j0gRRiyNdGms13YBUt4-sC%2BMg%40mail.gmail.com
> <https://groups.google.com/d/msgid/elixir-lang-core/CABu8xFBC%3DM6s0p9po2CsoWXQ-j0gRRiyNdGms13YBUt4-sC%2BMg%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/CADp0H2jKfmArDz6bPNnH71bEwHqYtethh8CzsprrCTwE8oB7YQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to