Re: [elixir-core:8371] Re: Runtime typespecs assertion

2018-11-07 Thread Louis Pilfold
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  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  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,  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 

Re: [elixir-core:8371] Re: Runtime typespecs assertion

2018-11-07 Thread Sergiy Kukunin
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  > 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,  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