October 21, 2008

Очень строгая типизация

Волею судеб я теперь играюсь с F#. (Сначала вроде бы увлёкся Haskell’ом, но потом понял, что F# мне как-то ближе, потому как он весь насквозь .net-ный). Если кто не знает, то язык этот – первый и пока что, кажется, единственный функциональный язык для платформы .net. Любители тонкостей скажут, что не такой уж он и функциональный, скорее мультипарадигменный (ох и сложное слово, надо его спеллчекером…), и будут правы. Так и есть, но я лично рассматриваю его как площадку для игр с функциональным программированием. И вот до чего я доигрался.

Есть у меня один микропроект. Даже не проект, а так, игрушка, которую я решил реализовать на F#, чтобы и утилитку полезную получить и с новым языком разобраться. Писал я писал, разбирался-разбирался и в один прекрасный момент понадобилось мне создать web запрос, да не простой, а с кукисами. Как бы я поступил в C#:

HttpWebRequest req =
(HttpWebRequest)WebRequest.Create("http://google.com");
req.CookieContainer.Add(new Cookie("my_cookie", "hello"));

Самая главная часть этого небольшого куска кода во второй строке, где создаётся WebRequest. Видите, как занимательно его приходится создавать? При помощи WebRequest.Create, который уже сам определяет какой конкретный тип запроса надо создать. В данном случае он создаст HttpWebRequest, поэтому преобразование типа здесь отлично сработает и даст нам доступ ко всем методам и свойствам, которые присущи http запросу.

В чём сложность с точки зрения F#? Как оказалось, в его строгой типизации.

let req = WebRequest.Create("http://google.com")
(* will cause an error *)
let httpreq = req :> HttpWebRequest

Архитектура библиотеки классов, как оказалось, не предполагает возможности создания экземпляров HttpWebRequest самих по себе, всё происходит исключительно через WebRequest.Create, а приведение типа объекта от более общего к более частному, получается, невозможно, а CookieContainer есть только в конкретном типе. Я пытался использовать обходные пути, типа Convert.ChangeType, но он, оказывается, возвращает вообще Object, и в итоге необходимо ещё более невозможное приведение типа :-)

Вот такая вот слишком строгая типизация. Если у кого есть мысли как это обойти – welcome!


Comments:
let httpreq = ((box req) :?> HttpWebRequest)

На самом деле боксинг тут вроде не нужен, должно работать и с простым динамическим кастингом...

let httpreq = req :?> HttpWebRequest

 


Вот спасибо так спасибо!
А главное, как только ввёл правильные слова "dynamic cast" в поиск, сразу всё нашлось.

 


На здоровье :-) Все никак не найду времени сесть и основательно заняться этим чудом вражеской мысли

 


Кстати, я тут нашёл в свободном совершенно доступе книгу Foundations of F#. Если вдруг...

 


Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?