Upgrade to Pro — share decks privately, control downloads, hide ads and more …

メタプログラミングとは

sunnyone
April 09, 2016

 メタプログラミングとは

2016.04.09

sunnyone

April 09, 2016
Tweet

More Decks by sunnyone

Other Decks in Programming

Transcript

  1. C言語の例(glib) #define G_IMPLEMENT_INTERFACE(TYPE_IFACE, iface_init) { \ const GInterfaceInfo g_implement_interface_info =

    { \ (GInterfaceInitFunc) iface_init, NULL, NULL \ }; \ g_type_add_interface_static (g_define_type_id, TYPE_IFACE, &g_implement_interface_info); \ } G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, gtk_entry_editable_init) glib の GLib Object SystemはマクロとC言語の仕様を駆使して、 C言語上にクラス/インタフェース構造を表現できるようにしている。 https://developer.gnome.org/gobject/stable/gtype-instantiable-classed.html gtype.h (https://github.com/GNOME/glib/blob/master/gobject/gtype.h)
  2. Rustの例 macro_rules! try { ($expr:expr) => (match $expr { $crate::result::Result::Ok(val)

    => val, $crate::result::Result::Err(err) => { return $crate::result::Result::Err($crate::convert::From::from(err)) } }) } fn write_to_file_using_try() -> Result<(), io::Error> { let mut file = try!(File::create("my_best_friends.txt")); try!(file.write_all(b"This is a list of my best friends.")); println!("I wrote to the file"); Ok(()) } 標準のtry! マクロ (https://github.com/rust-lang/rust/blob/master/src/libcore/macros.rs) このマクロの意味はRust bookのエラーハンドリングを参照 https://rust-lang-ja.github.io/the-rust-programming-language-ja/1.6/book/error-handling.html
  3. Ruby • 普段のメソッドなどの定義そのものがmoduleやclassなどのス コープに入って定義を追加する処理 • コードが動作時に行われることを明示的に実行する – NewClass = Class.new

    do ... end – define_method :new_method do ... end – send によるメソッド呼び出し – method_missing / respond_to – class_eval / instance_eval / module_eval
  4. Rubyの例(ActiveRecord) def method_missing(name, *arguments, &block) match = Method.match(self, name) if

    match && match.valid? match.define send(name, *arguments, &block) else super end end dynamic_matchers.rb (https://github.com/rails/rails/blob/4-2-stable/activerecord/lib/active_record/dynamic_matchers.rb) 定義する def define model.class_eval <<-CODE, __FILE__, __LINE__ + 1 def self.#{name}(#{signature}) #{body} end CODE end 呼び出す Client.find_by_first_name("HogeHoge")
  5. Pythonの例(boto3) def resource(self, service_name, region_name=None, api_version=None, (略) # Create the

    service resource class. cls = self.resource_factory.load_from_definition( resource_name=service_name, single_resource_json_definition=resource_model['service'], service_context=service_context ) return cls(client=client) session.py (https://github.com/boto/boto3/blob/develop/boto3/session.py) def load_from_definition(self, resource_name, single_resource_json_definition, service_context): (略) # Create the name based on the requested service and resource cls_name = resource_name if service_context.service_name == resource_name: cls_name = 'ServiceResource' cls_name = service_context.service_name + '.' + cls_name base_classes = [ServiceResource] (略) return type(str(cls_name), tuple(base_classes), attrs) s3 = boto3.resource('s3')
  6. Javaの例(ModelMapper) static Class<?> proxyClassFor(Class<?> type, Errors errors) throws ErrorsException {

    Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(type); enhancer.setUseFactory(true); enhancer.setUseCache(true); enhancer.setNamingPolicy(NAMING_POLICY); enhancer.setCallbackFilter(METHOD_FILTER); enhancer.setCallbackTypes(new Class[] { MethodInterceptor.class, NoOp.class }); try { return enhancer.createClass(); } catch (Throwable t) { throw errors.errorEnhancingClass(type, t).toException(); } } ProxyFactory.java (https://github.com/jhalterman/modelmapper/blob/master/core/src/main/java/org/modelmapper/internal/ProxyFactory.java) private static void setCallbacks(Object enhanced, MethodInterceptor interceptor) throws Exception { Field callback1 = enhanced.getClass().getDeclaredField("CGLIB$CALLBACK_0"); callback1.setAccessible(true); callback1.set(enhanced, interceptor); 呼び出し毎にinvoke()してくれる interceptするように継承したクラスを生成
  7. C#(Expression Tree)の例(LightNode) // (object[] args) => { new X().M((T1)args[0], (T2)args[1])...

    } var lambda = Expression.Lambda<Action<IDictionary<string, object>, object[]>>( Expression.Call( Expression.MemberInit(Expression.New(classType), envBind), methodInfo, parameters), envArg, args); this.handlerBodyType = HandlerBodyType.Action; this.methodActionBody = lambda.Compile(); OperationHandler.cs (https://github.com/neuecc/LightNode/blob/master/Source/LightNode.Server/OperationHandler.cs) handler.methodActionBody(environment, methodParameters);