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 <sergey.kuku...@gmail.com> 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 <sergey....@gmail.com> 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, <ivan.y...@gmail.com> 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 elixir-lang-co...@googlegroups.com.
>>>>
>>>>
>>>>> 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 elixir-lang-co...@googlegroups.com.
>>>
>> 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 elixir-lang-core+unsubscr...@googlegroups.com.
> 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 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/CABu8xFBC%3DM6s0p9po2CsoWXQ-j0gRRiyNdGms13YBUt4-sC%2BMg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to