Показаны сообщения с ярлыком python. Показать все сообщения
Показаны сообщения с ярлыком python. Показать все сообщения

2013-05-08

Много видал я извращений с макросами, но такого ...

Cello is a GNU99 C library which brings higher level programming to C.

Interfaces allow for structured design;
Duck Typing allows for generic functions;
Exceptions control error handling;
Constructors/Destructors aid memory management;

Ссылки на примеры:
Пример программы:

#include "Cello.h"

int main(int argc, char** argv) {

  /* Tables require "Eq" and "Hash" on key type */
  var prices = new(Table, String, Int);
  put(prices, $(String, "Apple"),  $(Int, 12)); 
  put(prices, $(String, "Banana"), $(Int,  6)); 
  put(prices, $(String, "Pear"),   $(Int, 55));

  /* Tables also supports iteration */
  foreach (key in prices) {
    var price = get(prices, key);
    print("Price of %$ is %$\n", key, price);
  }

  /* "with" automatically closes file at end of scope. */
  with (file in open($(File, NULL), "prices.bin", "wb"))) {

    /* First class function object */
    lambda(write_pair, args) {

      /* Run time type-checking with "cast" */
      var key = cast(at(args, 0), String);
      var val = cast(get(prices, key), Int);

      try {
        print_to(file, 0, "%$ :: %$\n", key, val);
      } catch (e in IOError) {
        println("Could not write to file - got %$", e)
      }

      return None;
    };

    /* Higher order functions */
    map(prices, write_pair);
  }

  delete(prices);
}

На что только люди не пойдут, чтоб на С++ не писать.

2013-03-06

6 дней работы над новым старым проектом.


>python svn-diffstat.py -rXXX
22 files changed: 2741 insertions(+), 4069 deletions(-) = -1328

svn-diffstat.py, если че.

2012-06-27

записки из генераторной

python-скрипт читает конфиг в ini-файле и создает файл, включаемый в Makefile.am.
Тот после обработки automake дает Makefile, который при make создает из XML-файлов .cpp и .h (через qdbusxml2cpp).
полученный h-файл обрабатывается moc, давая еще один .cpp.
Потом все это компилируется...

2012-04-25

ObjC vs Java

Серия постов о том, чего, по мнению Java-программиста, не хватает в ObjectiveC.
Ну, и мои мысли по этому поводу.
TL;DR: Отсутствие namespace и ручное управление памятью -- зло. ObjC -- не мой любимый язык.
  1. дженерики  для динамического языка не очень критичны (в питоне, к примеру, их нет, а в ActionScript -- есть всего один дженерик)
  2. Нет абстрактных методов. Согласен. С точки зрения "классического" ооп, отсутствие abstract и protected методов не дает задать контракт между базовым и дочерними классами. Приходится извращаться с методами, бросающими исключение -- что работает только при нормальном покрытии юнит-тестами. 
  3. Хидер+Реализация(*.h/*.m) vs один файл. Спорное высказывание. Хотя с одним файлом работать и удобнее, наличие отдельно вынесенного публичного интерфейса есть хорошо.
  4. Пространства имен. ППКС. Отсутствие пакетов или пространств имен в объектно-ориентированном языке -- это, мягко говоря, извращение. 
  5. Исключения.  В ObjC они более "многословны", чем в других языках, на этом, имхо, все отличия и заканчиваются. 
Из других минусов языка автор не назвал многословность (да-да, тот самый синтаксический оверхед :) ). Возможно, потому, что по сравнению с явой он не столь велик.
Защитники ObjC скажут "зато имя метода отражает, что он делает", но методы вида
- (NSRect)splitView:(NSSplitView *)splitView effectiveRect:(NSRect)proposedEffectiveRect forDrawnRect:(NSRect)drawnRect ofDividerAtIndex:(NSInteger)dividerIndex или константы длиной в 65 символов это тот случай, когда, сфокусировавшись на деревьях, не видно леса.

Кроме длинных идентификаторов, многословность вызвана еще одним недостатком языка:
Авторы языка так и не смогли определиться с управлением памятью.

В Managed языках все просто -- там изначально есть GC.

В C++ есть деструкторы объектов на стеке, что привело к концепции "умных" указателей: сперва пусть кривой, но стандартный std::auto_ptr, потом появились труды Александреску, бустовкие intrusive_ptr и shared_ptr/weak_ptr, которые и стали стандартом сначала де-факто, а потом и де-юре.
Move-semantic в С++11 с одной стороны, была революцией (как писали авторы стандарта -- "мы сломали почти все книги о эффективном программировании на С++"), с другой -- слегка поменялась форма, но не содержание -- заворачиваем объект в умный указатель и расслабляемся.

В ObjC же управление памятью развивалось этапами.

Изначально временем жизни управлял сам программист, создавая объект через метод класса alloc и управляя его жизнью, увеличивая счетчик ссылок через retain и уменьшая его вызовом release. То есть ручное управление временем жизни объектов. И сдесь разработчики допустили еще одну ошибку: они сделали создание объекта двухфазным: сперва выделение памяти (обычно alloc), потом инициализация (init или initWith...).  Изначально это было сделано для поддержки кастомного распределителя памяти (allocWithZone:), но, по-моему, этим никто никогда не пользовался. Получаем запись вида
Type * x = [[Type alloc] initWith:y];

И тут появляется хитрая политика владения: если в названии метода есть слова copy, alloc, new, то метод возвращает объект с увеличенным счетчиком ссылок, иначе -- с тем-же. То есть, налицо попытка решения технической задачи административным путем.  
Ну, и проблему циклических ссылок никто не отменял. 

Потом появилась концепция Autorelease Pool. Объекты, зарегистрированные в нем, удаляются при очистке пула, если на них больше никто не ссылается. Пулы образуют свой стек, что позволяет при выходе из метода, к примеру, подчистить за собой (ну, если не забыть вызвать у пула drain или release];
У стандартных классов появились методы вида [Type typeWithY:y], возвращающие объект в полумертвом состоянии (уже зарегистрированным в текущем авторелиз пуле) 
И вместо того, чтобы переделать стандартную библиотеку, объявив цепочку alloc-init deprecated, разработчки языка пошли по легкому пути и просто добавили autorelease в базовый класс.
А теперь сравните код

TypeX * x = [[[TypeX alloc] initWithTypeY:[[[TypeY alloc] initWithY:y] autorelease]] autorelease];
и 
TypeX x = TypeY(y); // Если на стеке

// или, если объекты выделять в куче.
std::shared_ptr<TypeX> x = std::make_shared<TypeX>(std::make_shared<TypeY>(y));


В ObjC 2.0 добавили свойства, что позволило не копипастить типичный для геттеров и сеттеров код. Но управление членами класса осталось на том-же уровне (retain в init, release в dealloc, если забыл - то ССЗБ)

Потом был GC, который объявили deprecated быстрее, чем он стал мейнстримом. Ну, не deprecated, но "ARC is preferable now". Automatic Reference Counting - это автоматическая вставка retain/release, если статический анализатор Clang считает, что они тут нужны. Если имена ваших методов следуют административным ограничениям (увеличивающие кол-во ссылок методы содержат слово alloc, copy, new, retain ; не меняющие -- не содержат; плюс несколько макросов/ключевых слов типа __strong или __weak), то все будет хорошо.

Если у вас есть циклические ссылки или кто-то нарушил правила  - ой. Хорошо если просто утечка, но может быть и дабл-фри. Который крайне тяжело отлаживать, ибо падает обычно внутри Autorelease Pool.

После того, как некоторое время пописал на ObjC, дико хочется обратно на C++.


2010-12-20

Автоматическое обновление svn:externals

В текущем проекте через svn:externals подключается 25 либ, причем не в единый корень, а в нескольких местах (в 5 или 6 местах).
Написал тут скрипт, который автоматически выставляет экстерналы на нужные ревизии.

2010-06-25

Обрезалка ресурсов.

В VC2008sp1 и VC2010 в состав MFC входят новые классы для Ribbon-like UI.
Можно выбрать одну из пяти тем для приложения (aqua, blue, black, silver, windows7).
При статической компиляции внутрь экзешника попадают ресурсы всех тем.
Если в приложении есть переключение тем, это гуд.
А если Ваше приложение всегда должно быть одного цвета -- как то жалко тратить больше 700 KB на ресурсы, которые никогда не используются.
А если учесть то, что это PNG и они плохо жмутся пакерами...

Вот, набросал за часик на коленке питонячий скрипт, который это лечит.

import sys
from ctypes import *

w32 = windll.kernel32

def get_res_list(fname):
handle = w32.LoadLibraryW(fname)
if not handle:
return None

types = []

def types_callback(handle, t):
try:
types.append(cast(t, c_wchar_p).value)
except:
pass
return True

types_callback_t = CFUNCTYPE(c_void_p, c_wchar_p, c_long)
fun = types_callback_t(types_callback)
w32.EnumResourceTypesW(handle, fun, 0)

result = []

def names_callback(h, t, n):
try:
t = cast(t, c_wchar_p).value
n = cast(n, c_wchar_p).value
result.append((t,n))
except e:
print e
return True

names_callback_t = CFUNCTYPE(c_void_p, c_wchar_p, c_wchar_p, c_long)
fun = names_callback_t(names_callback)
for t in types:
w32.EnumResourceNamesW(handle, c_wchar_p(t), fun, 0)
w32.FreeLibrary(handle)
return result

NOT_USED = ('AQUA', 'SILVER', 'WINDOWS7', 'BLACK')
is_not_used = lambda x: x[1].split('_')[0] in NOT_USED

def remove_resources(fname, not_used):
handle = w32.BeginUpdateResourceW(fname, False)
if not handle:
return False
ok = True
try:
for t,n in not_used:
w32.UpdateResourceW(handle, t, n, 0x409, None, 0)
except e:
print e
ok = False
w32.EndUpdateResourceW(handle, not ok)
return ok


fname = u'd:\\app.exe'
not_used = filter(is_not_used, get_res_list(fname))
print remove_resources(fname, not_used)