C# to Swift

I was looking into converting a C# code to Swift (Silver). Have the .Net Core libraries (System, System.Linq been implemented in Swift (Silver). If they have how do I reference them?

Convert C# code:

import NLedger.Expressions
import NLedger.Scopus
import NLedger.Values
import System
import System.Collections.Generic
import System.Linq
import System.Text
import System.Threading.Tasks

open class Account : Scope {
private var _FullName: String! = nil
private var _XData: AccountXData! = nil
private var LookupItems: ExprOpCollection! = ExprOpCollection()

open override var description: String! {
	get {
		return String.Format("account {0}", FullName)
	}
}

public private(set) var Parent: Account! {
	get {
		return 
	}
	set {
		= newValue
	}
}

public private(set) var Name: String! {
	get {
		return 
	}
	set {
		= newValue
	}
}

public var Note: String! {
	get {
		return 
	}
	set {
		= newValue
	}
}

public private(set) var Accounts: IDictionary<String,Account>! {
	get {
		return 
	}
	set {
		= newValue
	}
}

public private(set) var Posts: IList<Post>! {
	get {
		return 
	}
	set {
		= newValue
	}
}

public private(set) var DeferredPosts: IDictionary<String,IList<Post>>! {
	get {
		return 
	}
	set {
		= newValue
	}
}

public var ValueExpr: Expr! {
	get {
		return 
	}
	set {
		= newValue
	}
}

public private(set) var Depth: Int32 {
	get {
		return 
	}
	set {
		= newValue
	}
}

public var IsKnownAccount: Bool {
	get {
		return 
	}
	set {
		= newValue
	}
}

public var IsTempAccount: Bool {
	get {
		return 
	}
	set {
		= newValue
	}
}

public var IsGeneratedAccount: Bool {
	get {
		return 
	}
	set {
		= newValue
	}
}

public var FullName: String! {
	get {
		return coalesce(_FullName, _FullName == GetFullName())
	}
}

public var XData: AccountXData! {
	get {
		return coalesce(_XData, _XData == AccountXData())
	}
}

public var HasXData: Bool = false
public static let UnknownName: String! = "Unknown"

public init() {
	Accounts = SortedDictionary<String,Account>()
	Posts = List<Post>()
	CreateLookupItems()
}

public init(_ parent: Account!, _ name: String!, _ note: String! = nil) {
	super.init()
	Parent = parent
	Depth = (Parent != nil ? Parent.Depth + 1 : 0)
	Name = name
	Note = coalesce(note, String.Empty)
}

public func HasXFlags(_ xDataFunc: Func<AccountXData,Bool>!) -> Bool {
	return HasXData & xDataFunc(XData)
}

public func FindAccount(_ acctName: String!, _ autoCreate: Bool = true) -> Account! {
	var account: Account!
	if Accounts.TryGetValue(acctName, &(account)) {
		return account
	}
	var first: String!
	var rest: String!
	var pos: Int32 = acctName.IndexOf(":")
	if pos < 0 {
		first = acctName
		rest = nil
	} else {
		first = acctName.Substring(0, pos)
		rest = acctName.Substring(pos + 1)
	}
	if !Accounts.TryGetValue(first, &(account)) {
		if !autoCreate {
			return nil
		}
		account = Account(self, first)
		//  An account created within a temporary or generated account is itself
		//  temporary or generated, so that the whole tree has the same status.
		if IsTempAccount {
			account.IsTempAccount = IsTempAccount
		}
		if IsGeneratedAccount {
			account.IsGeneratedAccount = IsGeneratedAccount
		}
		Accounts.Add(first, account)
	}
	if !String.IsNullOrEmpty(rest) {
		account = account.FindAccount(rest, autoCreate)
	}
	return account
}

public func FindAccountRe(_ regexp: String!) -> Account! {
	return DoFindAccountRe(self, Mask(regexp))
}

public func Amount(_ expr: Expr! = nil) -> Value! {
	if HasXData & XData.Visited {
		for i in XData.SelfDetails.LastPost ... Posts.Count - 1 {
			var post: Post! = Posts[i]
			if post.XData.Visited & !post.XData.Considered {
				XData.SelfDetails.Total = post.AddToValue(XData.SelfDetails.Total, expr)
				post.XData.Considered = true
			}
		}
		XData.SelfDetails.LastPost = Posts.Count
		for i in XData.SelfDetails.LastReportedPost ... XData.ReportedPosts.Count - 1 {
			var post: Post! = XData.ReportedPosts[i]
			if post.XData.Visited & !post.XData.Considered {
				XData.SelfDetails.Total = post.AddToValue(XData.SelfDetails.Total, expr)
				post.XData.Considered = true
			}
		}
		XData.SelfDetails.LastReportedPost = XData.ReportedPosts.Count
		return XData.SelfDetails.Total
	} else {
		return Value()
	}
}

private func GetFullName() -> String! {
	var first: Account! = self
	var sb: StringBuilder! = StringBuilder(Name)
	while first.Parent != nil {
		first = first.Parent
		if !String.IsNullOrEmpty(first.Name) {
			sb.Insert(0, first.Name + ":")
		}
	}return sb.ToString()
}

public func AddAccount(_ acct: Account!) {
	Accounts[acct.Name] = acct
}

public func RemoveAccount(_ acct: Account!) -> Bool {
	if Accounts.ContainsKey(acct.Name) {
		Accounts.Remove(acct.Name)
		return true
	} else {
		return false
	}
}

public func AddPost(_ post: Post!) {
	Posts.Add(post)
	//  Adding a new post changes the possible totals that may have been
	//  computed before.
	if XData != nil {
		XData.SelfDetails.Gathered = false
		XData.SelfDetails.Calculated = false
		XData.FamilyDetails.Gathered = false
		XData.FamilyDetails.Calculated = false
	}
}

public func RemovePost(_ post: Post!) -> Bool {
	//  It's possible that 'post' wasn't yet in this account, but try to
	//  remove it anyway.  This can happen if there is an error during
	//  parsing, when the posting knows what it's account is, but
	//  xact_t::finalize has not yet added that posting to the account.
	Posts.Remove(post)
	post.Account = nil
	return true
}

public func AddDeferredPosts(_ uuid: String!, _ post: Post!) {
	if DeferredPosts == nil {
		DeferredPosts = Dictionary<String,IList<Post>>()
	}
	var posts: IList<Post>!
	if !DeferredPosts.TryGetValue(uuid, &(posts)) {
		DeferredPosts[uuid] = posts == List<Post>()
	}
	posts.Add(post)
}

public func GetDeferredPosts(_ uuid: String!) -> IEnumerable<Post>! {
	if DeferredPosts != nil {
		var posts: IList<Post>!
		if DeferredPosts.TryGetValue(uuid, &(posts)) {
			return posts
		}
	}
	return nil
}

public func DeleteDeferredPosts(_ uuid: String!) {
	if DeferredPosts != nil {
		DeferredPosts.Remove(uuid)
	}
}

public func ApplyDeferredPosts() {
	if DeferredPosts != nil {
		for post in DeferredPosts.Values.SelectMany({ (list) in
			list
		}) {
			post.Account.AddPost(post)
		}
		DeferredPosts = nil
	}
	//  Also apply in child accounts
	for account in Accounts.Values {
		account.ApplyDeferredPosts()
	}
}

public func ClearXData() {
	_XData = nil
	for account in Accounts.Values.Where({ (acc) in
		!acc.IsTempAccount
	}) {
		account.ClearXData()
	}
}

public func SetFlags(_ account: Account!) {
	IsKnownAccount = account.IsKnownAccount
	IsTempAccount = account.IsTempAccount
	IsGeneratedAccount = account.IsGeneratedAccount
}

public func SelfDetails(_ gatherAll: Bool = true) -> AccountXDataDetails! {
	if !HasXData & XData.SelfDetails.Gathered {
		self.XData.SelfDetails.Gathered = true
		for post in Posts {
			XData.SelfDetails.Update(post, gatherAll)
		}
	}
	return XData.SelfDetails
}

public func FamilyDetails(_ gatherAll: Bool = true) -> AccountXDataDetails! {
	if !HasXData & XData.FamilyDetails.Gathered {
		self.XData.FamilyDetails.Gathered = true
		for pair in Accounts {
			XData.FamilyDetails.Add(pair.Value.FamilyDetails(gatherAll))
		}
		XData.FamilyDetails.Add(SelfDetails(gatherAll))
	}
	return XData.FamilyDetails
}

open override func Lookup(_ kind: SymbolKindEnum!, _ name: String!) -> ExprOp! {
	return LookupItems.Lookup(kind, name, self)
}

public func PartialName(_ flat: Bool) -> String! {
	var sb: StringBuilder! = StringBuilder(Name)
	var acct: Account! = Parent
	while acct != nil & acct.Parent != nil {
		if !flat {
			var count: Int32 = acct.ChildrenWithFlags(true, false)
			if count == 0 {
				throw InvalidOperationException("assert(count > 0);")
			}
			if (count > 1) | (acct.HasXData & acct.XData.ToDisplay) {
				break
			}
		}
		sb.Insert(0, acct.Name + ":")
		acct = acct.Parent
	}return sb.ToString()
}

public func Total(_ expr: Expr! = nil) -> Value! {
	if !HasXData & XData.FamilyDetails.Calculated {
		XData.FamilyDetails.Calculated = true
		var temp: Value!
		for acct in Accounts.Values {
			temp = acct.Total(expr)
			if !Value.IsNullOrEmpty(temp) {
				XData.FamilyDetails.Total = Value.AddOrSetValue(XData.FamilyDetails.Total, temp)
			}
		}
		temp = Amount(expr)
		if !Value.IsNullOrEmpty(temp) {
			XData.FamilyDetails.Total = Value.AddOrSetValue(XData.FamilyDetails.Total, temp)
		}
	}
	return XData.FamilyDetails.Total
}

public func ChildrenWithFlags(_ toDisplay: Bool, _ visited: Bool) -> Int32 {
	var count: Int32 = 0
	var grandchildrenVisited: Bool = false
	for account in Accounts.Values {
		if (account.HasXData & HasXFlags(account.XData, toDisplay, visited)) | (account.ChildrenWithFlags(toDisplay, visited) > 0) {
			inc(count)
		}
	}
	//  Although no immediately children were visited, if any progeny at all were
	//  visited, it counts as one.
	if (count == 0) & grandchildrenVisited {
		count = 1
	}
	return count
}

open override func ToString() -> String! {
	return FullName
}

private static func HasXFlags(_ xdata: AccountXData!, _ toDisplay: Bool, _ visited: Bool) -> Bool {
	if toDisplay & !xdata.ToDisplay {
		return false
	}
	if visited & !xdata.Visited {
		return false
	}
	return toDisplay | visited
}

// #region Lookup Functions
private static func GetWrapper(_ scope: CallScope!, _ `func`: Func<Account,Value>!) -> Value! {
	return `func`(ScopeExtensions.FindScope<Account>(scope))
}

private static func GetAmount(_ account: Account!) -> Value! {
	return Value.SimplifiedValueOrZero(account.Amount())
}

private static func GetAccount(_ args: CallScope!) -> Value! {
	var account: Account! = args.Context<Account>()
	if args.Has(0) {
		var acct: Account! = account.Parent
		while acct != nil {
			acct = acct.Parent
		}if args[0].Type == ValueTypeEnum.String {
			return Value.ScopeValue(acct.FindAccount(args.Get(0), false))
		} else {
			if args[0].Type == ValueTypeEnum.Mask {
				return Value.ScopeValue(acct.FindAccountRe(args.Get<Mask>(0).ToString()))
			} else {
				return Value.Empty
			}
		}
	} else {
		if args.TypeContext == ValueTypeEnum.Scope {
			return Value.ScopeValue(account)
		} else {
			return Value.StringValue(account.FullName)
		}
	}
}

private static func FnAny(_ args: CallScope!) -> Value! {
	var account: Account! = args.Context<Account>()
	var expr: ExprOp! = args.Get<ExprOp>(0)
	for p in account.Posts {
		var boundScope: BindScope! = BindScope(args, p)
		if expr.Calc(boundScope, args.Locus, args.Depth).AsBoolean {
			return Value.True
		}
	}
	return Value.False
}

private static func FnAll(_ args: CallScope!) -> Value! {
	var account: Account! = args.Context<Account>()
	var expr: ExprOp! = args.Get<ExprOp>(0)
	for p in account.Posts {
		var boundScope: BindScope! = BindScope(args, p)
		if !expr.Calc(boundScope, args.Locus, args.Depth).AsBoolean {
			return Value.False
		}
	}
	return Value.True
}

private static func GetCount(_ account: Account!) -> Value! {
	return Value.Get(account.FamilyDetails().PostsCount)
}

private static func GetCost(_ account: Account!) -> Value! {
	throw CalcError(CalcError.ErrorMessageAnAccountDoesNotHaveACostValue)
}

private static func GetDepth(_ account: Account!) -> Value! {
	return Value.Get(account.Depth)
}

private static func GetDepthSpacer(_ account: Account!) -> Value! {
	var depth: Int32 = 0
	var acct: Account! = account.Parent
	while acct != nil & acct.Parent != nil {
		var count: Int32 = acct.ChildrenWithFlags(true, false)
		if count == 0 {
			throw InvalidOperationException("assert(count > 0)")
		}
		if (count > 1) | (acct.HasXData & acct.XData.ToDisplay) {
			inc(depth)
		}
		acct = acct.Parent
	}return Value.StringValue(String(" ", depth * 2))
}

private static func GetEarliest(_ account: Account!) -> Value! {
	return Value.Get(account.SelfDetails().EarliestPost)
}

private static func GetEarliestCheckin(_ account: Account!) -> Value! {
	return (account.SelfDetails().EarliestCheckin != nil ? Value.Get(account.SelfDetails().EarliestCheckin) : Value.Empty)
}

private static func GetSubcount(_ account: Account!) -> Value! {
	return Value.Get(account.SelfDetails().PostsCount)
}

private static func GetLatestCleared(_ account: Account!) -> Value! {
	return Value.Get(account.SelfDetails().LatestClearedPost)
}

private static func GetLatest(_ account: Account!) -> Value! {
	return Value.Get(account.SelfDetails().LatestPost)
}

private static func GetLatestCheckout(_ account: Account!) -> Value! {
	return (account.SelfDetails().LatestCheckout != nil ? Value.Get(account.SelfDetails().LatestCheckout) : Value.Empty)
}

private static func GetLatestCheckoutCleared(_ account: Account!) -> Value! {
	return Value.Get(account.SelfDetails().LatestCheckoutCleared)
}

private static func GetNote(_ account: Account!) -> Value! {
	return (!String.IsNullOrEmpty(account.Note) ? Value.StringValue(account.Note) : Value.Empty)
}

private static func GetPartialName(_ args: CallScope!) -> Value! {
	return Value.StringValue(args.Context<Account>().PartialName(args.Has(0) & args.Get(0)))
}

private static func GetTotal(_ account: Account!) -> Value! {
	return Value.SimplifiedValueOrZero(account.Total())
}

private func CreateLookupItems() {
	//  a
	LookupItems.MakeFunctor("a", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetAmount(a)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("amount", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetAmount(a)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("account", { (scope) in
		GetAccount((scope as? CallScope))
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("account_base", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			Value.StringValue(a.Name)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("addr", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			Value.Get(a)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("any", { (scope) in
		FnAny((scope as? CallScope))
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("all", { (scope) in
		FnAll((scope as? CallScope))
	}, SymbolKindEnum.FUNCTION)
	//  c
	LookupItems.MakeFunctor("count", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetCount(a)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("cost", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetCost(a)
		})
	}, SymbolKindEnum.FUNCTION)
	//  d
	LookupItems.MakeFunctor("depth", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetDepth(a)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("depth_spacer", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetDepthSpacer(a)
		})
	}, SymbolKindEnum.FUNCTION)
	//  e
	LookupItems.MakeFunctor("earliest", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetEarliest(a)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("earliest_checkin", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetEarliestCheckin(a)
		})
	}, SymbolKindEnum.FUNCTION)
	//  i
	LookupItems.MakeFunctor("is_account", { (scope) in
		Value.True
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("is_index", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetSubcount(a)
		})
	}, SymbolKindEnum.FUNCTION)
	//  l
	LookupItems.MakeFunctor("l", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetDepth(a)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("latest_cleared", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetLatestCleared(a)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("latest", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetLatest(a)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("latest_checkout", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetLatestCheckout(a)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("latest_checkout_cleared", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetLatestCheckoutCleared(a)
		})
	}, SymbolKindEnum.FUNCTION)
	//  n
	LookupItems.MakeFunctor("n", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetSubcount(a)
		})
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("note", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetNote(a)
		})
	}, SymbolKindEnum.FUNCTION)
	//  p
	LookupItems.MakeFunctor("partial_account", { (scope) in
		GetPartialName((scope as? CallScope))
	}, SymbolKindEnum.FUNCTION)
	LookupItems.MakeFunctor("parent", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			Value.ScopeValue(a.Parent)
		})
	}, SymbolKindEnum.FUNCTION)
	//  s
	LookupItems.MakeFunctor("subcount", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetSubcount(a)
		})
	}, SymbolKindEnum.FUNCTION)
	//  t
	LookupItems.MakeFunctor("total", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetTotal(a)
		})
	}, SymbolKindEnum.FUNCTION)
	//  u
	LookupItems.MakeFunctor("use_direct_amount", { (scope) in
		Value.False
	}, SymbolKindEnum.FUNCTION)
	//  N
	LookupItems.MakeFunctor("N", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetCount(a)
		})
	}, SymbolKindEnum.FUNCTION)
	//  O
	LookupItems.MakeFunctor("O", { (scope) in
		GetWrapper((scope as? CallScope), { (a) in
			GetTotal(a)
		})
	}, SymbolKindEnum.FUNCTION)
}

// #endregion
private func DoFindAccountRe(_ account: Account!, _ regex: Mask!) -> Account! {
	if regex.Match(account.FullName) {
		return account
	}
	for acc in account.Accounts.Values {
		var result: Account! = DoFindAccountRe(acc, regex)
		if result != nil {
			return result
		}
	}
	return nil
}

}

Brian,

three things on this

  1. Silver (and Elements in general) makes a string distinction between language (“Swift”, “C#”, etc) and platform (.NET, Java, Cocoa, etc). This blog post goes into this in more detail. All the .NET libraries are available to Silver directly, when targeting thew .NET platform — they dont need to be "(re-)implemented for Swift, per se, you can just reference them (eg System.Core.dll, which is actually referenced by default) and use them.

  2. for LINQ specifically, we actually do implement a large subset of that for the other platforms, so you can use LINQ on Java, Cocoa and .NET (from any language).

  3. Finally, what Swift as a language currently does not have is a language syntax for LINQ, so you will need to use the LINQ operator methods directly (ie “myList.Where($0 > 5);” where in C#'d you;'d do “from I in myList where I > 5;

Does that make sense?

(Unrelated, for converting code make sure to check out Oxidixer and the “Paste C# as Swift” menu, for a timesaver over full manual code conversion. Note also that you can mis Swift and C# code in the same project (regardless of platform) with Elements, as well)