36
FP vs. OOP In Void-Safety Context @STeplyakov & @AntyaDev

Void safety on Kiev ALT.NET

Embed Size (px)

DESCRIPTION

Slides from my talk at Kiev ALT.NET from 7/29. Sources: https://gist.github.com/SergeyTeplyakov/a1fbd8b2bb192009b650

Citation preview

Page 1: Void safety on Kiev ALT.NET

FP vs. OOPIn Void-Safety Context

@STeplyakov & @AntyaDev

Page 2: Void safety on Kiev ALT.NET

С чего все началось?

• Интервью с Бертраном Мейером (http://bit.ly/IntervewWithMeyer)

• Борьба с «нулевыми» ссылками в C# (http://bit.ly/VoidSafetyCSharp)

Page 3: Void safety on Kiev ALT.NET
Page 4: Void safety on Kiev ALT.NET

Ошибка на миллиард долларов«Я называю это своей ошибкой на миллиард долларов. Речь идет о изобретении нулевых ссылок (null reference) в 1965 году.»

http://bit.ly/BillionDollarMistake

Page 5: Void safety on Kiev ALT.NET
Page 6: Void safety on Kiev ALT.NET
Page 7: Void safety on Kiev ALT.NET

[CanBeNull]public static IClrTypeName GetCallSiteTypeNaive(IInvocationExpression invocationExpression){    Contract.Requires(invocationExpression != null);

    if (invocationExpression.InvokedExpression != null)    {        var referenceExpression = invocationExpression.InvokedExpression as IReferenceExpression;        if (referenceExpression != null)        {            var resolved = referenceExpression.Reference.Resolve();            if (resolved.DeclaredElement != null)            {                var declared = resolved.DeclaredElement as IClrDeclaredElement;                if (declared != null)                {                    var containingType = declared.GetContainingType();                    if (containingType != null)                    {                        return containingType.GetClrName();                    }                }            }        }    }

    return null;}

Page 8: Void safety on Kiev ALT.NET
Page 9: Void safety on Kiev ALT.NET

Void-Safety. Подходы

• ОО-подходы

• Not-nullable reference types: Eiffel, Swift (*), Spec#, C++ (**)

• Contracts

• ФП-подходы

• Maybe<T>

• Отсутствие литерала null (***)

Page 10: Void safety on Kiev ALT.NET

Void-Safety в C#

• Not-nullable reference types in C# (*)

• null-propagating operator (C# 6.0)

• Code Contracts

• Explicit Maybe types

• Implicit maybe type + extension methods

http://bit.ly/VoidSafetyCSharp

Page 11: Void safety on Kiev ALT.NET

Not-nullable reference types// Где-то в идеальном мире// s – not-nullable переменнаяpublic void Foo(string s){    // Никакие проверки, контркты, атрибуты не нужны    Console.WriteLine(s.Length);}

// str – nullable (detached) переменная. //string! аналогичен типу Option<string>public void Boo(string! str){    // Ошибка компиляции!    // Нельзя обращаться к членам "detached" строки!    // Console.WriteLine(str.Length);    str.IfAttached((string s) => Console.WriteLine(s));    // Или    if (str != null)        Console.WriteLine(str.Length);}

public void Doo(string! str){    Contract.Requires(str != null);    // Наличие предусловия позволяет безопасным образом    // обращаться к объекте string через ссылку str!    Console.WriteLine(str.Length);}

Page 12: Void safety on Kiev ALT.NET

No non-nullable reference types in C#

In theory, theory and practice are the same, but in practice, they’re different. This is no exception. There are many pragmatic objections to adding non-nullable reference types now. 

Eric Lippert

http://blog.coverity.com/2013/11/20/c-non-nullable-reference-types/

Page 13: Void safety on Kiev ALT.NET

Альтернатива по Липперту?

Code Contracts!

Page 14: Void safety on Kiev ALT.NET

Let the fight begin

Page 15: Void safety on Kiev ALT.NET

Как функциональные программисты заменяют лампочки? Они не заменяют лампочки, а покупают новую розетку, новую электропроводку и новую лампочку.

Бертран Мейер

Page 16: Void safety on Kiev ALT.NET

NoException?!

Let’s review this: http://ericlippert.com/2013/03/21/monads-part-nine/

Page 17: Void safety on Kiev ALT.NET
Page 18: Void safety on Kiev ALT.NET

А что Эрик думает по этому поводу?

[1. This technique can be dangerous, in that it can delay the production of an exception until long after the exception handlers designed to deal with it are no longer on the stack. Worse, it can delay the production of an exception indefinitely, leading to programs that should have crashed continuing to corrupt user data. Use with extreme caution.]

http://ericlippert.com/2013/03/21/monads-part-nine/

Page 19: Void safety on Kiev ALT.NET

В чем проблема с Maybe<T>?

• Оптимизация на corner case

• Lack of DogFooding!

• Какую проблему мы решаем?

• Void-safety или упрощение control flow?

• Дополнительные затраты на обучение

• Отсутствие паттерн-матчинга

• Подход не универсален! (*)

• Чем не подходит implicit monads + CanBeNull/Postconditions?

Page 20: Void safety on Kiev ALT.NET

Оптимизация на corner case-е!

• Источники:

• “Declaring and Checking Non-null Types” by Manuel Fahndrich, K. Rustan M. Leino, Microsoft Research

• “Avoid a Void: The eradication of null dereferencing” by Bertrand Meyer et al

Page 21: Void safety on Kiev ALT.NET

Так какую проблему мы решаем?

• Void Safety vs. Control Flow simplification

• Как выразить non-nullable с помощью Monad?

Page 22: Void safety on Kiev ALT.NET

public static class MaybeExtensions {     public static A Match<T, A>(this Maybe<T> maybe, Func<A> none, Func<T, A> some)     {         return maybe == null || maybe.IsNone ? none() : some(maybe.Value);     }

public static Maybe<A> Bind<T, A>(this Maybe<T> maybe, Func<T, A> func)     {         return func == null || maybe == null || maybe.IsNone             ? new Maybe<A>()             : func(maybe.Value).ToMaybe();     } }

Page 23: Void safety on Kiev ALT.NET

Семантика NRE?

Page 24: Void safety on Kiev ALT.NET

I don't need Maybe, I need non-nullable

reference types!

Page 25: Void safety on Kiev ALT.NET

Мой подход?

Code Contracts + Annotations + Extension methods for reference types!

(+ R# plugin - https://resharper-plugins.jetbrains.com/packages/ReSharper.ContractExtensions/)

Page 26: Void safety on Kiev ALT.NET

Контракты? Нет, не слышали!

• Assert-ы на стероидах!

• Выражают смысл (семантику) кода

• Выразительность, бла, бла, бла…

• Pet Project: https://github.com/SergeyTeplyakov/ReSharperContractExtensions

Page 27: Void safety on Kiev ALT.NET

var contractFunction = GetContractFunction();if (contractFunction == null){    AddContractClass();

    contractFunction = GetContractFunction();    Contract.Assert(contractFunction != null);}

AddRequiresTo(contractFunction);

...

[CanBeNull, System.Diagnostics.Contracts.Pure]private ICSharpFunctionDeclaration GetContractFunction(){    return _availability.SelectedFunction.GetContractFunction();}

Page 28: Void safety on Kiev ALT.NET
Page 29: Void safety on Kiev ALT.NET

Maybe + Contracts?

Page 30: Void safety on Kiev ALT.NET

[CanBeNull]public static IClrTypeName GetCallSiteTypeNaive(IInvocationExpression invocationExpression){    Contract.Requires(invocationExpression != null);

    if (invocationExpression.InvokedExpression != null)    {        var referenceExpression = invocationExpression.InvokedExpression as IReferenceExpression;        if (referenceExpression != null)        {            var resolved = referenceExpression.Reference.Resolve();            if (resolved.DeclaredElement != null)            {                var declared = resolved.DeclaredElement as IClrDeclaredElement;                if (declared != null)                {                    var containingType = declared.GetContainingType();                    if (containingType != null)                    {                        return containingType.GetClrName();                    }                }            }        }    }

    return null;}

Page 31: Void safety on Kiev ALT.NET

Implicit monads[CanBeNull]public static IClrTypeName GetCallSiteType(this IInvocationExpression invocationExpression){    Contract.Requires(invocationExpression != null);

    var type = invocationExpression        .With(x => x.InvokedExpression)        .With(x => x as IReferenceExpression)        .With(x => x.Reference)        .With(x => x.Resolve())        .With(x => x.DeclaredElement)        .With(x => x as IClrDeclaredElement)        .With(x => x.GetContainingType())        .Return(x => x.GetClrName());    return type;}

Page 32: Void safety on Kiev ALT.NET

Caveats!

var hashCode = invocationExpression    .With(x => x.InvokedExpression)    .With(x => x as IReferenceExpression)    .With(x => x.Reference)    .With(x => x.Resolve())    .With(x => x.GetHashCode());

var hashCode = invocationExpression    .With(x => x.InvokedExpression)    .With(x => x as IReferenceExpression)    .With(x => x.Reference)    .With(x => x.Resolve())    .ReturnStruct(x => x.GetHashCode());

Compile-time error!

hachCode – это int?

Page 33: Void safety on Kiev ALT.NET
Page 34: Void safety on Kiev ALT.NET
Page 35: Void safety on Kiev ALT.NET

Null-propagating operator ?. (C# 6.0)

https://roslyn.codeplex.com/discussions/540883

Page 36: Void safety on Kiev ALT.NET